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