TianoCore EDK2 master
Loading...
Searching...
No Matches
Elf32Lib.c
Go to the documentation of this file.
1
9#include "ElfLibInternal.h"
10
21 IN UINT8 *ImageBase,
22 IN UINT32 Index
23 )
24{
25 Elf32_Ehdr *Ehdr;
26
27 Ehdr = (Elf32_Ehdr *)ImageBase;
28 if (Index >= Ehdr->e_shnum) {
29 return NULL;
30 }
31
32 return (Elf32_Shdr *)(ImageBase + Ehdr->e_shoff + Index * Ehdr->e_shentsize);
33}
34
45 IN UINT8 *ImageBase,
46 IN UINT32 Index
47 )
48{
49 Elf32_Ehdr *Ehdr;
50
51 Ehdr = (Elf32_Ehdr *)ImageBase;
52 if (Index >= Ehdr->e_phnum) {
53 return NULL;
54 }
55
56 return (Elf32_Phdr *)(ImageBase + Ehdr->e_phoff + Index * Ehdr->e_phentsize);
57}
58
70 IN UINT8 *ImageBase,
71 IN UINT32 Offset,
72 IN UINT32 Size
73 )
74{
75 UINT32 Index;
76 Elf32_Ehdr *Ehdr;
77 Elf32_Shdr *Shdr;
78
79 Ehdr = (Elf32_Ehdr *)ImageBase;
80
81 Shdr = (Elf32_Shdr *)(ImageBase + Ehdr->e_shoff);
82 for (Index = 0; Index < Ehdr->e_shnum; Index++) {
83 if ((Shdr->sh_offset == Offset) && (Shdr->sh_size == Size)) {
84 return Shdr;
85 }
86
87 Shdr = ELF_NEXT_ENTRY (Elf32_Shdr, Shdr, Ehdr->e_shentsize);
88 }
89
90 return NULL;
91}
92
107 IN Elf32_Rela *Rela,
108 IN UINT32 RelaSize,
109 IN UINT32 RelaEntrySize,
110 IN UINT32 RelaType,
111 IN INTN Delta,
112 IN BOOLEAN DynamicLinking
113 )
114{
115 UINTN Index;
116 UINT32 *Ptr;
117 UINT32 Type;
118
119 for ( Index = 0
120 ; RelaEntrySize * Index < RelaSize
121 ; Index++, Rela = ELF_NEXT_ENTRY (Elf32_Rela, Rela, RelaEntrySize)
122 )
123 {
124 //
125 // r_offset is the virtual address of the storage unit affected by the relocation.
126 //
127 Ptr = (UINT32 *)(UINTN)(Rela->r_offset + Delta);
128 Type = ELF32_R_TYPE (Rela->r_info);
129 switch (Type) {
130 case R_386_NONE:
131 case R_386_PC32:
132 //
133 // No fixup entry required.
134 //
135 break;
136
137 case R_386_32:
138 if (DynamicLinking) {
139 //
140 // Dynamic section doesn't contain entries of this type.
141 //
142 DEBUG ((DEBUG_INFO, "Unsupported relocation type %02X\n", Type));
143 ASSERT (FALSE);
144 } else {
145 *Ptr += (UINT32)Delta;
146 }
147
148 break;
149
150 case R_386_RELATIVE:
151 if (DynamicLinking) {
152 //
153 // A: Represents the addend used to compute the value of the relocatable field.
154 // B: Represents the base address at which a shared object has been loaded into memory during execution.
155 // Generally, a shared object is built with a 0 base virtual address, but the execution address will be different.
156 //
157 // B (Base Address) in ELF spec is slightly different:
158 // An executable or shared object file's base address (on platforms that support the concept) is calculated during
159 // execution from three values: the virtual memory load address, the maximum page size, and the lowest virtual address
160 // of a program's loadable segment. To compute the base address, one determines the memory address associated with the
161 // lowest p_vaddr value for a PT_LOAD segment. This address is truncated to the nearest multiple of the maximum page size.
162 // The corresponding p_vaddr value itself is also truncated to the nearest multiple of the maximum page size.
163 //
164 // *** The base address is the difference between the truncated memory address and the truncated p_vaddr value. ***
165 //
166 // Delta in this function is B.
167 //
168 // Calculation: B + A
169 //
170 if (RelaType == SHT_RELA) {
171 *Ptr = (UINT32)Delta + Rela->r_addend;
172 } else {
173 //
174 // A is stored in the field of relocation for REL type.
175 //
176 *Ptr = (UINT32)Delta + *Ptr;
177 }
178 } else {
179 //
180 // non-Dynamic section doesn't contain entries of this type.
181 //
182 DEBUG ((DEBUG_INFO, "Unsupported relocation type %02X\n", Type));
183 ASSERT (FALSE);
184 }
185
186 break;
187
188 default:
189 DEBUG ((DEBUG_INFO, "Unsupported relocation type %02X\n", Type));
190 }
191 }
192
193 return EFI_SUCCESS;
194}
195
206 IN ELF_IMAGE_CONTEXT *ElfCt
207 )
208{
209 UINT32 Index;
210 Elf32_Phdr *Phdr;
211 Elf32_Shdr *DynShdr;
212 Elf32_Shdr *RelShdr;
213 Elf32_Dyn *Dyn;
214 UINT32 RelaAddress;
215 UINT32 RelaCount;
216 UINT32 RelaSize;
217 UINT32 RelaEntrySize;
218 UINT32 RelaType;
219
220 //
221 // 1. Locate the dynamic section.
222 //
223 // If an object file participates in dynamic linking, its program header table
224 // will have an element of type PT_DYNAMIC.
225 // This ``segment'' contains the .dynamic section. A special symbol, _DYNAMIC,
226 // labels the section, which contains an array of Elf32_Dyn or Elf64_Dyn.
227 //
228 DynShdr = NULL;
229 for (Index = 0; Index < ElfCt->PhNum; Index++) {
230 Phdr = GetElf32SegmentByIndex (ElfCt->FileBase, Index);
231 ASSERT (Phdr != NULL);
232 if (Phdr->p_type == PT_DYNAMIC) {
233 //
234 // Verify the existence of the dynamic section.
235 //
236 DynShdr = GetElf32SectionByRange (ElfCt->FileBase, Phdr->p_offset, Phdr->p_filesz);
237 break;
238 }
239 }
240
241 //
242 // It's abnormal a DYN ELF doesn't contain a dynamic section.
243 //
244 ASSERT (DynShdr != NULL);
245 if (DynShdr == NULL) {
246 return EFI_UNSUPPORTED;
247 }
248
249 ASSERT (DynShdr->sh_type == SHT_DYNAMIC);
250 ASSERT (DynShdr->sh_entsize >= sizeof (*Dyn));
251
252 //
253 // 2. Locate the relocation section from the dynamic section.
254 //
255 RelaAddress = MAX_UINT32;
256 RelaSize = 0;
257 RelaCount = 0;
258 RelaEntrySize = 0;
259 RelaType = 0;
260 for ( Index = 0, Dyn = (Elf32_Dyn *)(ElfCt->FileBase + DynShdr->sh_offset)
261 ; Index < DynShdr->sh_size / DynShdr->sh_entsize
262 ; Index++, Dyn = ELF_NEXT_ENTRY (Elf32_Dyn, Dyn, DynShdr->sh_entsize)
263 )
264 {
265 switch (Dyn->d_tag) {
266 case DT_RELA:
267 case DT_REL:
268 //
269 // DT_REL represent program virtual addresses.
270 // A file's virtual addresses might not match the memory virtual addresses during execution.
271 // When interpreting addresses contained in the dynamic structure, the dynamic linker computes actual addresses,
272 // based on the original file value and the memory base address.
273 // For consistency, files do not contain relocation entries to ``correct'' addresses in the dynamic structure.
274 //
275 RelaAddress = Dyn->d_un.d_ptr;
276 RelaType = (Dyn->d_tag == DT_RELA) ? SHT_RELA : SHT_REL;
277 break;
278 case DT_RELACOUNT:
279 case DT_RELCOUNT:
280 RelaCount = Dyn->d_un.d_val;
281 break;
282 case DT_RELENT:
283 case DT_RELAENT:
284 RelaEntrySize = Dyn->d_un.d_val;
285 break;
286 case DT_RELSZ:
287 case DT_RELASZ:
288 RelaSize = Dyn->d_un.d_val;
289 break;
290 default:
291 break;
292 }
293 }
294
295 if (RelaAddress == MAX_UINT32) {
296 ASSERT (RelaCount == 0);
297 ASSERT (RelaEntrySize == 0);
298 ASSERT (RelaSize == 0);
299 //
300 // It's fine that a DYN ELF doesn't contain relocation section.
301 //
302 return EFI_SUCCESS;
303 }
304
305 //
306 // Verify the existence of the relocation section.
307 //
308 RelShdr = NULL;
309 for (Index = 0; Index < ElfCt->ShNum; Index++) {
310 RelShdr = GetElf32SectionByIndex (ElfCt->FileBase, Index);
311 ASSERT (RelShdr != NULL);
312 if ((RelShdr->sh_addr == RelaAddress) && (RelShdr->sh_size == RelaSize)) {
313 break;
314 }
315
316 RelShdr = NULL;
317 }
318
319 if (RelShdr == NULL) {
320 return EFI_UNSUPPORTED;
321 }
322
323 ASSERT (RelShdr->sh_type == RelaType);
324 ASSERT (RelShdr->sh_entsize == RelaEntrySize);
325
326 //
327 // 3. Process the relocation section.
328 //
330 (Elf32_Rela *)(ElfCt->FileBase + RelShdr->sh_offset),
331 RelShdr->sh_size,
332 RelShdr->sh_entsize,
333 RelShdr->sh_type,
334 (UINTN)ElfCt->ImageAddress - (UINTN)ElfCt->PreferredImageAddress,
335 TRUE
336 );
337 return EFI_SUCCESS;
338}
339
350 IN ELF_IMAGE_CONTEXT *ElfCt
351 )
352{
353 EFI_STATUS Status;
354 Elf32_Ehdr *Ehdr;
355 Elf32_Shdr *RelShdr;
356 Elf32_Shdr *Shdr;
357 UINT32 Index;
358 UINTN Delta;
359
360 Ehdr = (Elf32_Ehdr *)ElfCt->FileBase;
361 if (Ehdr->e_machine != EM_386) {
362 return EFI_UNSUPPORTED;
363 }
364
365 Delta = (UINTN)ElfCt->ImageAddress - (UINTN)ElfCt->PreferredImageAddress;
366 ElfCt->EntryPoint = (UINTN)(Ehdr->e_entry + Delta);
367
368 //
369 // 1. Relocate dynamic ELF using the relocation section pointed by dynamic section
370 //
371 if (Ehdr->e_type == ET_DYN) {
372 DEBUG ((DEBUG_INFO, "DYN ELF: Relocate using dynamic sections...\n"));
373 Status = RelocateElf32Dynamic (ElfCt);
374 ASSERT_EFI_ERROR (Status);
375 return Status;
376 }
377
378 //
379 // 2. Executable ELF: Fix up the delta between actual image address and preferred image address.
380 //
381 // Linker already fixed up EXEC ELF based on the preferred image address.
382 // A ELF loader in modern OS only loads it into the preferred image address.
383 // The below relocation is unneeded in that case.
384 // But the ELF loader in firmware supports to load the image to a different address.
385 // The below relocation is needed in this case.
386 //
387 DEBUG ((DEBUG_INFO, "EXEC ELF: Fix actual/preferred base address delta ...\n"));
388 for ( Index = 0, RelShdr = (Elf32_Shdr *)(ElfCt->FileBase + Ehdr->e_shoff)
389 ; Index < Ehdr->e_shnum
390 ; Index++, RelShdr = ELF_NEXT_ENTRY (Elf32_Shdr, RelShdr, Ehdr->e_shentsize)
391 )
392 {
393 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {
394 continue;
395 }
396
397 Shdr = GetElf32SectionByIndex (ElfCt->FileBase, RelShdr->sh_info);
398 if ((Shdr->sh_flags & SHF_ALLOC) == SHF_ALLOC) {
399 //
400 // Only fix up sections that occupy memory during process execution.
401 //
403 (Elf32_Rela *)((UINT8 *)Ehdr + RelShdr->sh_offset),
404 RelShdr->sh_size,
405 RelShdr->sh_entsize,
406 RelShdr->sh_type,
407 Delta,
408 FALSE
409 );
410 }
411 }
412
413 return EFI_SUCCESS;
414}
415
431 IN ELF_IMAGE_CONTEXT *ElfCt
432 )
433{
434 Elf32_Ehdr *Ehdr;
435 Elf32_Phdr *Phdr;
436 UINT16 Index;
437 UINTN Delta;
438
439 ASSERT (ElfCt != NULL);
440
441 //
442 // Per the sprit of ELF, loading to memory only consumes info from program headers.
443 //
444 Ehdr = (Elf32_Ehdr *)ElfCt->FileBase;
445
446 for ( Index = 0, Phdr = (Elf32_Phdr *)(ElfCt->FileBase + Ehdr->e_phoff)
447 ; Index < Ehdr->e_phnum
448 ; Index++, Phdr = ELF_NEXT_ENTRY (Elf32_Phdr, Phdr, Ehdr->e_phentsize)
449 )
450 {
451 //
452 // Skip segments that don't require load (type tells, or size is 0)
453 //
454 if ((Phdr->p_type != PT_LOAD) ||
455 (Phdr->p_memsz == 0))
456 {
457 continue;
458 }
459
460 //
461 // The memory offset of segment relative to the image base
462 // Note: CopyMem() does nothing when the dst equals to src.
463 //
464 Delta = Phdr->p_paddr - (UINT32)(UINTN)ElfCt->PreferredImageAddress;
465 CopyMem (ElfCt->ImageAddress + Delta, ElfCt->FileBase + Phdr->p_offset, Phdr->p_filesz);
466 ZeroMem (ElfCt->ImageAddress + Delta + Phdr->p_filesz, Phdr->p_memsz - Phdr->p_filesz);
467 }
468
469 //
470 // Relocate when new new image base is not the preferred image base.
471 //
472 if (ElfCt->ImageAddress != ElfCt->PreferredImageAddress) {
473 RelocateElf32Sections (ElfCt);
474 }
475
476 return EFI_SUCCESS;
477}
UINT64 UINTN
INT64 INTN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
Elf32_Phdr * GetElf32SegmentByIndex(IN UINT8 *ImageBase, IN UINT32 Index)
Definition: Elf32Lib.c:44
EFI_STATUS LoadElf32Image(IN ELF_IMAGE_CONTEXT *ElfCt)
Definition: Elf32Lib.c:430
EFI_STATUS ProcessRelocation32(IN Elf32_Rela *Rela, IN UINT32 RelaSize, IN UINT32 RelaEntrySize, IN UINT32 RelaType, IN INTN Delta, IN BOOLEAN DynamicLinking)
Definition: Elf32Lib.c:106
EFI_STATUS RelocateElf32Sections(IN ELF_IMAGE_CONTEXT *ElfCt)
Definition: Elf32Lib.c:349
EFI_STATUS RelocateElf32Dynamic(IN ELF_IMAGE_CONTEXT *ElfCt)
Definition: Elf32Lib.c:205
Elf32_Shdr * GetElf32SectionByRange(IN UINT8 *ImageBase, IN UINT32 Offset, IN UINT32 Size)
Definition: Elf32Lib.c:69
Elf32_Shdr * GetElf32SectionByIndex(IN UINT8 *ImageBase, IN UINT32 Index)
Definition: Elf32Lib.c:20
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112