]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFw/Elf32Convert.c
License header updated to match correct format.
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf32Convert.c
CommitLineData
f51461c8 1/** @file\r
97fa0ee9 2Elf32 Convert solution\r
f51461c8 3\r
97fa0ee9 4Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
f51461c8
LG
5Portions copyright (c) 2013, ARM Ltd. All rights reserved.<BR>\r
6\r
7This program and the accompanying materials are licensed and made available\r
8under the terms and conditions of the BSD License which accompanies this\r
9distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "WinNtInclude.h"\r
18\r
19#ifndef __GNUC__\r
20#include <windows.h>\r
21#include <io.h>\r
22#endif\r
23#include <assert.h>\r
24#include <stdio.h>\r
25#include <stdlib.h>\r
26#include <string.h>\r
27#include <time.h>\r
28#include <ctype.h>\r
29\r
30#include <Common/UefiBaseTypes.h>\r
31#include <IndustryStandard/PeImage.h>\r
32\r
33#include "PeCoffLib.h"\r
34#include "EfiUtilityMsgs.h"\r
35\r
36#include "GenFw.h"\r
37#include "ElfConvert.h"\r
38#include "Elf32Convert.h"\r
39\r
40STATIC\r
41VOID\r
42ScanSections32 (\r
43 VOID\r
44 );\r
45\r
46STATIC\r
47BOOLEAN\r
48WriteSections32 (\r
49 SECTION_FILTER_TYPES FilterType\r
50 );\r
51\r
52STATIC\r
53VOID\r
54WriteRelocations32 (\r
55 VOID\r
56 );\r
57\r
58STATIC\r
59VOID\r
60WriteDebug32 (\r
61 VOID\r
62 );\r
63\r
64STATIC\r
65VOID\r
66SetImageSize32 (\r
67 VOID\r
68 );\r
69\r
70STATIC\r
71VOID\r
72CleanUp32 (\r
73 VOID\r
74 );\r
75\r
76//\r
77// Rename ELF32 strucutres to common names to help when porting to ELF64.\r
78//\r
79typedef Elf32_Shdr Elf_Shdr;\r
80typedef Elf32_Ehdr Elf_Ehdr;\r
81typedef Elf32_Rel Elf_Rel;\r
82typedef Elf32_Sym Elf_Sym;\r
83typedef Elf32_Phdr Elf_Phdr;\r
84typedef Elf32_Dyn Elf_Dyn;\r
85#define ELFCLASS ELFCLASS32\r
86#define ELF_R_TYPE(r) ELF32_R_TYPE(r)\r
87#define ELF_R_SYM(r) ELF32_R_SYM(r)\r
88\r
89//\r
90// Well known ELF structures.\r
91//\r
92STATIC Elf_Ehdr *mEhdr;\r
93STATIC Elf_Shdr *mShdrBase;\r
94STATIC Elf_Phdr *mPhdrBase;\r
95\r
96//\r
97// Coff information\r
98//\r
99STATIC const UINT32 mCoffAlignment = 0x20;\r
100\r
101//\r
102// PE section alignment.\r
103//\r
104STATIC const UINT16 mCoffNbrSections = 5;\r
105\r
106//\r
107// ELF sections to offset in Coff file.\r
108//\r
109STATIC UINT32 *mCoffSectionsOffset = NULL;\r
110\r
111//\r
112// Offsets in COFF file\r
113//\r
114STATIC UINT32 mNtHdrOffset;\r
115STATIC UINT32 mTextOffset;\r
116STATIC UINT32 mDataOffset;\r
117STATIC UINT32 mHiiRsrcOffset;\r
118STATIC UINT32 mRelocOffset;\r
119\r
120//\r
121// Initialization Function\r
122//\r
123BOOLEAN\r
124InitializeElf32 (\r
125 UINT8 *FileBuffer,\r
126 ELF_FUNCTION_TABLE *ElfFunctions\r
127 )\r
128{\r
129 //\r
130 // Initialize data pointer and structures.\r
131 //\r
132 mEhdr = (Elf_Ehdr*) FileBuffer; \r
133\r
134 //\r
135 // Check the ELF32 specific header information.\r
136 //\r
137 if (mEhdr->e_ident[EI_CLASS] != ELFCLASS32) {\r
138 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFCLASS32");\r
139 return FALSE;\r
140 }\r
141 if (mEhdr->e_ident[EI_DATA] != ELFDATA2LSB) {\r
142 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB");\r
143 return FALSE;\r
144 } \r
145 if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) {\r
146 Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN");\r
147 return FALSE;\r
148 }\r
149 if (!((mEhdr->e_machine == EM_386) || (mEhdr->e_machine == EM_ARM))) { \r
150 Error (NULL, 0, 3000, "Unsupported", "ELF e_machine not EM_386 or EM_ARM");\r
151 return FALSE;\r
152 }\r
153 if (mEhdr->e_version != EV_CURRENT) {\r
154 Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT);\r
155 return FALSE;\r
156 }\r
157 \r
158 //\r
159 // Update section header pointers\r
160 //\r
161 mShdrBase = (Elf_Shdr *)((UINT8 *)mEhdr + mEhdr->e_shoff);\r
162 mPhdrBase = (Elf_Phdr *)((UINT8 *)mEhdr + mEhdr->e_phoff);\r
163 \r
164 //\r
165 // Create COFF Section offset buffer and zero.\r
166 //\r
167 mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32));\r
168 memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32));\r
169\r
170 //\r
171 // Fill in function pointers.\r
172 //\r
173 ElfFunctions->ScanSections = ScanSections32;\r
174 ElfFunctions->WriteSections = WriteSections32;\r
175 ElfFunctions->WriteRelocations = WriteRelocations32;\r
176 ElfFunctions->WriteDebug = WriteDebug32;\r
177 ElfFunctions->SetImageSize = SetImageSize32;\r
178 ElfFunctions->CleanUp = CleanUp32;\r
179\r
180 return TRUE;\r
181}\r
182\r
183\r
184//\r
185// Header by Index functions\r
186//\r
187STATIC\r
188Elf_Shdr*\r
189GetShdrByIndex (\r
190 UINT32 Num\r
191 )\r
192{\r
193 if (Num >= mEhdr->e_shnum)\r
194 return NULL;\r
195 return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);\r
196}\r
197\r
198STATIC\r
199Elf_Phdr*\r
200GetPhdrByIndex (\r
201 UINT32 num\r
202 )\r
203{\r
204 if (num >= mEhdr->e_phnum) {\r
205 return NULL;\r
206 }\r
207\r
208 return (Elf_Phdr *)((UINT8*)mPhdrBase + num * mEhdr->e_phentsize);\r
209}\r
210\r
211STATIC\r
212UINT32\r
213CoffAlign (\r
214 UINT32 Offset\r
215 )\r
216{\r
217 return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);\r
218}\r
219\r
220//\r
221// filter functions\r
222//\r
223STATIC\r
224BOOLEAN\r
225IsTextShdr (\r
226 Elf_Shdr *Shdr\r
227 )\r
228{\r
229 return (BOOLEAN) ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC);\r
230}\r
231\r
232STATIC\r
233BOOLEAN\r
234IsHiiRsrcShdr (\r
235 Elf_Shdr *Shdr\r
236 )\r
237{\r
238 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
239\r
240 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);\r
241}\r
242\r
243STATIC\r
244BOOLEAN\r
245IsDataShdr (\r
246 Elf_Shdr *Shdr\r
247 )\r
248{\r
249 if (IsHiiRsrcShdr(Shdr)) {\r
250 return FALSE;\r
251 }\r
252 return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);\r
253}\r
254\r
255//\r
256// Elf functions interface implementation\r
257//\r
258\r
259STATIC\r
260VOID\r
261ScanSections32 (\r
262 VOID\r
263 )\r
264{\r
265 UINT32 i;\r
266 EFI_IMAGE_DOS_HEADER *DosHdr;\r
267 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
268 UINT32 CoffEntry;\r
269 UINT32 SectionCount;\r
270 BOOLEAN FoundText;\r
271\r
272 CoffEntry = 0;\r
273 mCoffOffset = 0;\r
274 mTextOffset = 0;\r
275 FoundText = FALSE;\r
276\r
277 //\r
278 // Coff file start with a DOS header.\r
279 //\r
280 mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;\r
281 mNtHdrOffset = mCoffOffset;\r
282 switch (mEhdr->e_machine) {\r
283 case EM_386:\r
284 case EM_ARM:\r
285 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32);\r
286 break;\r
287 default:\r
288 VerboseMsg ("%s unknown e_machine type. Assume IA-32", (UINTN)mEhdr->e_machine);\r
289 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32);\r
290 break;\r
291 }\r
292\r
293 mTableOffset = mCoffOffset;\r
294 mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);\r
295\r
296 //\r
297 // First text sections.\r
298 //\r
299 mCoffOffset = CoffAlign(mCoffOffset);\r
300 SectionCount = 0;\r
301 for (i = 0; i < mEhdr->e_shnum; i++) {\r
302 Elf_Shdr *shdr = GetShdrByIndex(i);\r
303 if (IsTextShdr(shdr)) {\r
304 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
305 // the alignment field is valid\r
306 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
307 // if the section address is aligned we must align PE/COFF\r
308 mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
309 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
310 // ARM RVCT tools have behavior outside of the ELF specification to try\r
311 // and make images smaller. If sh_addr is not aligned to sh_addralign\r
312 // then the section needs to preserve sh_addr MOD sh_addralign.\r
313 // Normally doing nothing here works great.\r
314 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
315 }\r
316 }\r
317\r
318 /* Relocate entry. */\r
319 if ((mEhdr->e_entry >= shdr->sh_addr) &&\r
320 (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {\r
321 CoffEntry = mCoffOffset + mEhdr->e_entry - shdr->sh_addr;\r
322 }\r
323\r
324 //\r
325 // Set mTextOffset with the offset of the first '.text' section\r
326 //\r
327 if (!FoundText) {\r
328 mTextOffset = mCoffOffset;\r
329 FoundText = TRUE;\r
330 }\r
331\r
332 mCoffSectionsOffset[i] = mCoffOffset;\r
333 mCoffOffset += shdr->sh_size;\r
334 SectionCount ++;\r
335 }\r
336 }\r
337\r
338 if (!FoundText) {\r
339 Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");\r
340 assert (FALSE);\r
341 }\r
342\r
343 if (mEhdr->e_machine != EM_ARM) {\r
344 mCoffOffset = CoffAlign(mCoffOffset);\r
345 }\r
346\r
347 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
348 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);\r
349 }\r
350\r
351 //\r
352 // Then data sections.\r
353 //\r
354 mDataOffset = mCoffOffset;\r
355 SectionCount = 0;\r
356 for (i = 0; i < mEhdr->e_shnum; i++) {\r
357 Elf_Shdr *shdr = GetShdrByIndex(i);\r
358 if (IsDataShdr(shdr)) {\r
359 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
360 // the alignment field is valid\r
361 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
362 // if the section address is aligned we must align PE/COFF\r
363 mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
364 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
365 // ARM RVCT tools have behavior outside of the ELF specification to try\r
366 // and make images smaller. If sh_addr is not aligned to sh_addralign\r
367 // then the section needs to preserve sh_addr MOD sh_addralign.\r
368 // Normally doing nothing here works great.\r
369 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
370 }\r
371 }\r
372 mCoffSectionsOffset[i] = mCoffOffset;\r
373 mCoffOffset += shdr->sh_size;\r
374 SectionCount ++;\r
375 }\r
376 }\r
377 mCoffOffset = CoffAlign(mCoffOffset);\r
378\r
379 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
380 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
381 }\r
382\r
383 //\r
384 // The HII resource sections.\r
385 //\r
386 mHiiRsrcOffset = mCoffOffset;\r
387 for (i = 0; i < mEhdr->e_shnum; i++) {\r
388 Elf_Shdr *shdr = GetShdrByIndex(i);\r
389 if (IsHiiRsrcShdr(shdr)) {\r
390 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
391 // the alignment field is valid\r
392 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
393 // if the section address is aligned we must align PE/COFF\r
394 mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
395 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
396 // ARM RVCT tools have behavior outside of the ELF specification to try\r
397 // and make images smaller. If sh_addr is not aligned to sh_addralign\r
398 // then the section needs to preserve sh_addr MOD sh_addralign.\r
399 // Normally doing nothing here works great.\r
400 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
401 }\r
402 }\r
403 if (shdr->sh_size != 0) {\r
404 mCoffSectionsOffset[i] = mCoffOffset;\r
405 mCoffOffset += shdr->sh_size;\r
406 mCoffOffset = CoffAlign(mCoffOffset);\r
407 SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);\r
408 }\r
409 break;\r
410 }\r
411 }\r
412\r
413 mRelocOffset = mCoffOffset;\r
414\r
415 //\r
416 // Allocate base Coff file. Will be expanded later for relocations.\r
417 //\r
418 mCoffFile = (UINT8 *)malloc(mCoffOffset);\r
419 memset(mCoffFile, 0, mCoffOffset);\r
420\r
421 //\r
422 // Fill headers.\r
423 //\r
424 DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;\r
425 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;\r
426 DosHdr->e_lfanew = mNtHdrOffset;\r
427\r
428 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);\r
429\r
430 NtHdr->Pe32.Signature = EFI_IMAGE_NT_SIGNATURE;\r
431\r
432 switch (mEhdr->e_machine) {\r
433 case EM_386:\r
434 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;\r
435 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
436 break;\r
437 case EM_ARM:\r
438 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_ARMT;\r
439 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
440 break;\r
441 default:\r
442 VerboseMsg ("%s unknown e_machine type. Assume IA-32", (UINTN)mEhdr->e_machine);\r
443 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;\r
444 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
445 }\r
446\r
447 NtHdr->Pe32.FileHeader.NumberOfSections = mCoffNbrSections;\r
448 NtHdr->Pe32.FileHeader.TimeDateStamp = (UINT32) time(NULL);\r
449 mImageTimeStamp = NtHdr->Pe32.FileHeader.TimeDateStamp;\r
450 NtHdr->Pe32.FileHeader.PointerToSymbolTable = 0;\r
451 NtHdr->Pe32.FileHeader.NumberOfSymbols = 0;\r
452 NtHdr->Pe32.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32.OptionalHeader);\r
453 NtHdr->Pe32.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE\r
454 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED\r
455 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED\r
456 | EFI_IMAGE_FILE_32BIT_MACHINE;\r
457\r
458 NtHdr->Pe32.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;\r
459 NtHdr->Pe32.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;\r
460 NtHdr->Pe32.OptionalHeader.SizeOfUninitializedData = 0;\r
461 NtHdr->Pe32.OptionalHeader.AddressOfEntryPoint = CoffEntry;\r
462\r
463 NtHdr->Pe32.OptionalHeader.BaseOfCode = mTextOffset;\r
464\r
465 NtHdr->Pe32.OptionalHeader.BaseOfData = mDataOffset;\r
466 NtHdr->Pe32.OptionalHeader.ImageBase = 0;\r
467 NtHdr->Pe32.OptionalHeader.SectionAlignment = mCoffAlignment;\r
468 NtHdr->Pe32.OptionalHeader.FileAlignment = mCoffAlignment;\r
469 NtHdr->Pe32.OptionalHeader.SizeOfImage = 0;\r
470\r
471 NtHdr->Pe32.OptionalHeader.SizeOfHeaders = mTextOffset;\r
472 NtHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
473\r
474 //\r
475 // Section headers.\r
476 //\r
477 if ((mDataOffset - mTextOffset) > 0) {\r
478 CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,\r
479 EFI_IMAGE_SCN_CNT_CODE\r
480 | EFI_IMAGE_SCN_MEM_EXECUTE\r
481 | EFI_IMAGE_SCN_MEM_READ);\r
482 } else {\r
483 // Don't make a section of size 0.\r
484 NtHdr->Pe32.FileHeader.NumberOfSections--;\r
485 }\r
486\r
487 if ((mHiiRsrcOffset - mDataOffset) > 0) {\r
488 CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,\r
489 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
490 | EFI_IMAGE_SCN_MEM_WRITE\r
491 | EFI_IMAGE_SCN_MEM_READ);\r
492 } else {\r
493 // Don't make a section of size 0.\r
494 NtHdr->Pe32.FileHeader.NumberOfSections--;\r
495 }\r
496\r
497 if ((mRelocOffset - mHiiRsrcOffset) > 0) {\r
498 CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,\r
499 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
500 | EFI_IMAGE_SCN_MEM_READ);\r
501\r
502 NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;\r
503 NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;\r
504 } else {\r
505 // Don't make a section of size 0.\r
506 NtHdr->Pe32.FileHeader.NumberOfSections--;\r
507 }\r
508\r
509}\r
510\r
511STATIC\r
512BOOLEAN\r
513WriteSections32 (\r
514 SECTION_FILTER_TYPES FilterType\r
515 )\r
516{\r
517 UINT32 Idx;\r
518 Elf_Shdr *SecShdr;\r
519 UINT32 SecOffset;\r
520 BOOLEAN (*Filter)(Elf_Shdr *);\r
521\r
522 //\r
523 // Initialize filter pointer\r
524 //\r
525 switch (FilterType) {\r
526 case SECTION_TEXT:\r
527 Filter = IsTextShdr;\r
528 break;\r
529 case SECTION_HII:\r
530 Filter = IsHiiRsrcShdr;\r
531 break;\r
532 case SECTION_DATA:\r
533 Filter = IsDataShdr;\r
534 break;\r
535 default:\r
536 return FALSE;\r
537 }\r
538\r
539 //\r
540 // First: copy sections.\r
541 //\r
542 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
543 Elf_Shdr *Shdr = GetShdrByIndex(Idx);\r
544 if ((*Filter)(Shdr)) {\r
545 switch (Shdr->sh_type) {\r
546 case SHT_PROGBITS:\r
547 /* Copy. */\r
548 memcpy(mCoffFile + mCoffSectionsOffset[Idx],\r
549 (UINT8*)mEhdr + Shdr->sh_offset,\r
550 Shdr->sh_size);\r
551 break;\r
552\r
553 case SHT_NOBITS:\r
554 memset(mCoffFile + mCoffSectionsOffset[Idx], 0, Shdr->sh_size);\r
555 break;\r
556\r
557 default:\r
558 //\r
559 // Ignore for unkown section type.\r
560 //\r
561 VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type);\r
562 break;\r
563 }\r
564 }\r
565 }\r
566\r
567 //\r
568 // Second: apply relocations.\r
569 //\r
570 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
571 //\r
572 // Determine if this is a relocation section.\r
573 //\r
574 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);\r
575 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {\r
576 continue;\r
577 }\r
578 \r
579 //\r
580 // Relocation section found. Now extract section information that the relocations\r
581 // apply to in the ELF data and the new COFF data.\r
582 //\r
583 SecShdr = GetShdrByIndex(RelShdr->sh_info);\r
584 SecOffset = mCoffSectionsOffset[RelShdr->sh_info];\r
585 \r
586 //\r
587 // Only process relocations for the current filter type.\r
588 //\r
589 if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {\r
590 UINT32 RelOffset;\r
591 \r
592 //\r
593 // Determine the symbol table referenced by the relocation data.\r
594 //\r
595 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);\r
596 UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;\r
597\r
598 //\r
599 // Process all relocation entries for this section.\r
600 //\r
601 for (RelOffset = 0; RelOffset < RelShdr->sh_size; RelOffset += RelShdr->sh_entsize) {\r
602 //\r
603 // Set pointer to relocation entry\r
604 //\r
605 Elf_Rel *Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelOffset);\r
606 \r
607 //\r
608 // Set pointer to symbol table entry associated with the relocation entry.\r
609 //\r
610 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);\r
611 \r
612 Elf_Shdr *SymShdr;\r
613 UINT8 *Targ;\r
614 UINT16 Address;\r
615\r
616 //\r
617 // Check section header index found in symbol table and get the section \r
618 // header location.\r
619 //\r
620 if (Sym->st_shndx == SHN_UNDEF\r
621 || Sym->st_shndx == SHN_ABS\r
622 || Sym->st_shndx > mEhdr->e_shnum) {\r
623 Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName);\r
624 }\r
625 SymShdr = GetShdrByIndex(Sym->st_shndx);\r
626\r
627 //\r
628 // Convert the relocation data to a pointer into the coff file.\r
629 //\r
630 // Note: \r
631 // r_offset is the virtual address of the storage unit to be relocated.\r
632 // sh_addr is the virtual address for the base of the section.\r
633 //\r
634 Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);\r
635\r
636 //\r
637 // Determine how to handle each relocation type based on the machine type.\r
638 //\r
639 if (mEhdr->e_machine == EM_386) {\r
640 switch (ELF_R_TYPE(Rel->r_info)) {\r
641 case R_386_NONE:\r
642 break;\r
643 case R_386_32:\r
644 //\r
645 // Absolute relocation.\r
646 // Converts Targ from a absolute virtual address to the absolute\r
647 // COFF address.\r
648 //\r
649 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr\r
650 + mCoffSectionsOffset[Sym->st_shndx];\r
651 break;\r
652 case R_386_PC32:\r
653 //\r
654 // Relative relocation: Symbol - Ip + Addend\r
655 //\r
656 *(UINT32 *)Targ = *(UINT32 *)Targ\r
657 + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)\r
658 - (SecOffset - SecShdr->sh_addr);\r
659 break;\r
660 default:\r
661 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
662 }\r
663 } else if (mEhdr->e_machine == EM_ARM) {\r
664 switch (ELF32_R_TYPE(Rel->r_info)) {\r
665 case R_ARM_RBASE:\r
666 // No relocation - no action required\r
667 // break skipped\r
668\r
669 case R_ARM_PC24:\r
670 case R_ARM_XPC25:\r
671 case R_ARM_THM_PC22:\r
672 case R_ARM_THM_JUMP19:\r
673 case R_ARM_CALL:\r
674 case R_ARM_JMP24:\r
675 case R_ARM_THM_JUMP24: \r
676 case R_ARM_PREL31: \r
677 case R_ARM_MOVW_PREL_NC: \r
678 case R_ARM_MOVT_PREL:\r
679 case R_ARM_THM_MOVW_PREL_NC:\r
680 case R_ARM_THM_MOVT_PREL:\r
681 case R_ARM_THM_JMP6:\r
682 case R_ARM_THM_ALU_PREL_11_0:\r
683 case R_ARM_THM_PC12:\r
684 case R_ARM_REL32_NOI:\r
685 case R_ARM_ALU_PC_G0_NC:\r
686 case R_ARM_ALU_PC_G0:\r
687 case R_ARM_ALU_PC_G1_NC:\r
688 case R_ARM_ALU_PC_G1:\r
689 case R_ARM_ALU_PC_G2:\r
690 case R_ARM_LDR_PC_G1:\r
691 case R_ARM_LDR_PC_G2:\r
692 case R_ARM_LDRS_PC_G0:\r
693 case R_ARM_LDRS_PC_G1:\r
694 case R_ARM_LDRS_PC_G2:\r
695 case R_ARM_LDC_PC_G0:\r
696 case R_ARM_LDC_PC_G1:\r
697 case R_ARM_LDC_PC_G2:\r
698 case R_ARM_GOT_PREL:\r
699 case R_ARM_THM_JUMP11:\r
700 case R_ARM_THM_JUMP8:\r
701 case R_ARM_TLS_GD32:\r
702 case R_ARM_TLS_LDM32:\r
703 case R_ARM_TLS_IE32:\r
704 // Thease are all PC-relative relocations and don't require modification\r
705 // GCC does not seem to have the concept of a application that just needs to get relocated.\r
706 break;\r
707\r
708 case R_ARM_THM_MOVW_ABS_NC:\r
709 // MOVW is only lower 16-bits of the addres\r
710 Address = (UINT16)(Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
711 ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);\r
712 break;\r
713\r
714 case R_ARM_THM_MOVT_ABS:\r
715 // MOVT is only upper 16-bits of the addres\r
716 Address = (UINT16)((Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]) >> 16);\r
717 ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);\r
718 break;\r
719\r
720 case R_ARM_ABS32:\r
721 case R_ARM_RABS32:\r
722 //\r
723 // Absolute relocation.\r
724 //\r
725 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
726 break;\r
727\r
728 default:\r
729 Error (NULL, 0, 3000, "Invalid", "WriteSections (): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));\r
730 }\r
731 }\r
732 }\r
733 }\r
734 }\r
735\r
736 return TRUE;\r
737}\r
738\r
739UINTN gMovwOffset = 0;\r
740\r
741STATIC\r
742VOID\r
743WriteRelocations32 (\r
744 VOID\r
745 )\r
746{\r
747 UINT32 Index;\r
748 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
749 EFI_IMAGE_DATA_DIRECTORY *Dir;\r
750 BOOLEAN FoundRelocations;\r
751 Elf_Dyn *Dyn;\r
752 Elf_Rel *Rel;\r
753 UINTN RelElementSize;\r
754 UINTN RelSize;\r
755 UINTN RelOffset;\r
756 UINTN K;\r
757 UINT8 *Targ;\r
758 Elf32_Phdr *DynamicSegment;\r
759 Elf32_Phdr *TargetSegment;\r
760\r
761 for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {\r
762 Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
763 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {\r
764 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);\r
765 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {\r
766 UINT32 RelIdx;\r
767\r
768 FoundRelocations = TRUE;\r
769 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {\r
770 Elf_Rel *Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
771\r
772 if (mEhdr->e_machine == EM_386) { \r
773 switch (ELF_R_TYPE(Rel->r_info)) {\r
774 case R_386_NONE:\r
775 case R_386_PC32:\r
776 //\r
777 // No fixup entry required.\r
778 //\r
779 break;\r
780 case R_386_32:\r
781 //\r
782 // Creates a relative relocation entry from the absolute entry.\r
783 //\r
784 CoffAddFixup(mCoffSectionsOffset[RelShdr->sh_info]\r
785 + (Rel->r_offset - SecShdr->sh_addr),\r
786 EFI_IMAGE_REL_BASED_HIGHLOW);\r
787 break;\r
788 default:\r
789 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
790 }\r
791 } else if (mEhdr->e_machine == EM_ARM) {\r
792 switch (ELF32_R_TYPE(Rel->r_info)) {\r
793 case R_ARM_RBASE:\r
794 // No relocation - no action required\r
795 // break skipped\r
796\r
797 case R_ARM_PC24:\r
798 case R_ARM_XPC25:\r
799 case R_ARM_THM_PC22:\r
800 case R_ARM_THM_JUMP19:\r
801 case R_ARM_CALL:\r
802 case R_ARM_JMP24:\r
803 case R_ARM_THM_JUMP24: \r
804 case R_ARM_PREL31: \r
805 case R_ARM_MOVW_PREL_NC: \r
806 case R_ARM_MOVT_PREL:\r
807 case R_ARM_THM_MOVW_PREL_NC:\r
808 case R_ARM_THM_MOVT_PREL:\r
809 case R_ARM_THM_JMP6:\r
810 case R_ARM_THM_ALU_PREL_11_0:\r
811 case R_ARM_THM_PC12:\r
812 case R_ARM_REL32_NOI:\r
813 case R_ARM_ALU_PC_G0_NC:\r
814 case R_ARM_ALU_PC_G0:\r
815 case R_ARM_ALU_PC_G1_NC:\r
816 case R_ARM_ALU_PC_G1:\r
817 case R_ARM_ALU_PC_G2:\r
818 case R_ARM_LDR_PC_G1:\r
819 case R_ARM_LDR_PC_G2:\r
820 case R_ARM_LDRS_PC_G0:\r
821 case R_ARM_LDRS_PC_G1:\r
822 case R_ARM_LDRS_PC_G2:\r
823 case R_ARM_LDC_PC_G0:\r
824 case R_ARM_LDC_PC_G1:\r
825 case R_ARM_LDC_PC_G2:\r
826 case R_ARM_GOT_PREL:\r
827 case R_ARM_THM_JUMP11:\r
828 case R_ARM_THM_JUMP8:\r
829 case R_ARM_TLS_GD32:\r
830 case R_ARM_TLS_LDM32:\r
831 case R_ARM_TLS_IE32:\r
832 // Thease are all PC-relative relocations and don't require modification\r
833 break;\r
834\r
835 case R_ARM_THM_MOVW_ABS_NC:\r
836 CoffAddFixup (\r
837 mCoffSectionsOffset[RelShdr->sh_info]\r
838 + (Rel->r_offset - SecShdr->sh_addr),\r
839 EFI_IMAGE_REL_BASED_ARM_MOV32T\r
840 );\r
841\r
842 // PE/COFF treats MOVW/MOVT relocation as single 64-bit instruction\r
843 // Track this address so we can log an error for unsupported sequence of MOVW/MOVT\r
844 gMovwOffset = mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr);\r
845 break;\r
846\r
847 case R_ARM_THM_MOVT_ABS:\r
848 if ((gMovwOffset + 4) != (mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr))) {\r
849 Error (NULL, 0, 3000, "Not Supported", "PE/COFF requires MOVW+MOVT instruction sequence %x +4 != %x.", gMovwOffset, mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
850 }\r
851 break;\r
852\r
853 case R_ARM_ABS32:\r
854 case R_ARM_RABS32:\r
855 CoffAddFixup (\r
856 mCoffSectionsOffset[RelShdr->sh_info]\r
857 + (Rel->r_offset - SecShdr->sh_addr),\r
858 EFI_IMAGE_REL_BASED_HIGHLOW\r
859 );\r
860 break;\r
861\r
862 default:\r
863 Error (NULL, 0, 3000, "Invalid", "WriteRelocations(): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));\r
864 }\r
865 } else {\r
866 Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);\r
867 }\r
868 }\r
869 }\r
870 }\r
871 }\r
872\r
873 if (!FoundRelocations && (mEhdr->e_machine == EM_ARM)) {\r
874 /* Try again, but look for PT_DYNAMIC instead of SHT_REL */\r
875\r
876 for (Index = 0; Index < mEhdr->e_phnum; Index++) {\r
877 RelElementSize = 0;\r
878 RelSize = 0;\r
879 RelOffset = 0;\r
880\r
881 DynamicSegment = GetPhdrByIndex (Index);\r
882\r
883 if (DynamicSegment->p_type == PT_DYNAMIC) {\r
884 Dyn = (Elf32_Dyn *) ((UINT8 *)mEhdr + DynamicSegment->p_offset);\r
885\r
886 while (Dyn->d_tag != DT_NULL) {\r
887 switch (Dyn->d_tag) {\r
888 case DT_REL:\r
889 RelOffset = Dyn->d_un.d_val;\r
890 break;\r
891\r
892 case DT_RELSZ:\r
893 RelSize = Dyn->d_un.d_val;\r
894 break;\r
895\r
896 case DT_RELENT:\r
897 RelElementSize = Dyn->d_un.d_val;\r
898 break;\r
899\r
900 default:\r
901 break;\r
902 }\r
903 Dyn++;\r
904 }\r
905 if (( RelOffset == 0 ) || ( RelSize == 0 ) || ( RelElementSize == 0 )) {\r
906 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName);\r
907 }\r
908\r
909 for (K = 0; K < RelSize; K += RelElementSize) {\r
910\r
911 if (DynamicSegment->p_paddr == 0) {\r
912 // Older versions of the ARM ELF (SWS ESPC 0003 B-02) specification define DT_REL\r
913 // as an offset in the dynamic segment. p_paddr is defined to be zero for ARM tools\r
914 Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + DynamicSegment->p_offset + RelOffset + K);\r
915 } else {\r
916 // This is how it reads in the generic ELF specification\r
917 Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + RelOffset + K);\r
918 }\r
919\r
920 switch (ELF32_R_TYPE (Rel->r_info)) {\r
921 case R_ARM_RBASE:\r
922 break;\r
923\r
924 case R_ARM_RABS32:\r
925 TargetSegment = GetPhdrByIndex (ELF32_R_SYM (Rel->r_info) - 1);\r
926\r
927 // Note: r_offset in a memory address. Convert it to a pointer in the coff file.\r
928 Targ = mCoffFile + mCoffSectionsOffset[ ELF32_R_SYM( Rel->r_info ) ] + Rel->r_offset - TargetSegment->p_vaddr;\r
929\r
930 *(UINT32 *)Targ = *(UINT32 *)Targ + mCoffSectionsOffset [ELF32_R_SYM( Rel->r_info )];\r
931\r
932 CoffAddFixup (mCoffSectionsOffset[ELF32_R_SYM (Rel->r_info)] + (Rel->r_offset - TargetSegment->p_vaddr), EFI_IMAGE_REL_BASED_HIGHLOW);\r
933 break;\r
934 \r
935 default:\r
936 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations, unkown type %d.", mInImageName, ELF32_R_TYPE (Rel->r_info));\r
937 break;\r
938 }\r
939 }\r
940 break;\r
941 }\r
942 }\r
943 }\r
944\r
945 //\r
946 // Pad by adding empty entries.\r
947 //\r
948 while (mCoffOffset & (mCoffAlignment - 1)) {\r
949 CoffAddFixupEntry(0);\r
950 }\r
951\r
952 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
953 Dir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
954 Dir->Size = mCoffOffset - mRelocOffset;\r
955 if (Dir->Size == 0) {\r
956 // If no relocations, null out the directory entry and don't add the .reloc section\r
957 Dir->VirtualAddress = 0;\r
958 NtHdr->Pe32.FileHeader.NumberOfSections--;\r
959 } else {\r
960 Dir->VirtualAddress = mRelocOffset;\r
961 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,\r
962 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
963 | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
964 | EFI_IMAGE_SCN_MEM_READ);\r
965 }\r
966\r
967}\r
968\r
969STATIC\r
970VOID\r
971WriteDebug32 (\r
972 VOID\r
973 )\r
974{\r
975 UINT32 Len;\r
976 UINT32 DebugOffset;\r
977 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
978 EFI_IMAGE_DATA_DIRECTORY *DataDir;\r
979 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;\r
980 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;\r
981\r
982 Len = strlen(mInImageName) + 1;\r
983 DebugOffset = mCoffOffset;\r
984\r
985 mCoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)\r
986 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)\r
987 + Len;\r
988 mCoffOffset = CoffAlign(mCoffOffset);\r
989\r
990 mCoffFile = realloc(mCoffFile, mCoffOffset);\r
991 memset(mCoffFile + DebugOffset, 0, mCoffOffset - DebugOffset);\r
992\r
993 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + DebugOffset);\r
994 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
995 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
996 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
997 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
998\r
999 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);\r
1000 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;\r
1001 strcpy ((char *)(Nb10 + 1), mInImageName);\r
1002\r
1003\r
1004 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
1005 DataDir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
1006 DataDir->VirtualAddress = DebugOffset;\r
1007 DataDir->Size = mCoffOffset - DebugOffset;\r
1008 if (DataDir->Size == 0) {\r
1009 // If no debug, null out the directory entry and don't add the .debug section\r
1010 DataDir->VirtualAddress = 0;\r
1011 NtHdr->Pe32.FileHeader.NumberOfSections--;\r
1012 } else {\r
1013 DataDir->VirtualAddress = DebugOffset;\r
1014 CreateSectionHeader (".debug", DebugOffset, mCoffOffset - DebugOffset,\r
1015 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
1016 | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
1017 | EFI_IMAGE_SCN_MEM_READ);\r
1018\r
1019 }\r
1020}\r
1021\r
1022STATIC\r
1023VOID\r
1024SetImageSize32 (\r
1025 VOID\r
1026 )\r
1027{\r
1028 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
1029 \r
1030 //\r
1031 // Set image size\r
1032 //\r
1033 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
1034 NtHdr->Pe32.OptionalHeader.SizeOfImage = mCoffOffset;\r
1035}\r
1036\r
1037STATIC\r
1038VOID\r
1039CleanUp32 (\r
1040 VOID\r
1041 )\r
1042{\r
1043 if (mCoffSectionsOffset != NULL) {\r
1044 free (mCoffSectionsOffset);\r
1045 }\r
1046}\r
1047\r
1048\r