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