|
From: <and...@us...> - 2010-03-24 17:29:28
|
Revision: 1941
http://edk2-buildtools.svn.sourceforge.net/edk2-buildtools/?rev=1941&view=rev
Author: andrewfish
Date: 2010-03-24 17:29:20 +0000 (Wed, 24 Mar 2010)
Log Message:
-----------
Add support for ARM MOVW & MOVT relocations. These relocations are different than other relocations as each instruction only enocodes 1/2 of the 32-bit address so the MOVT that encodes the upper 16-bits requires Addend info in the relocation entry. This is done via Elf32_Rela in ELF by adding the Addend into the relocation data. Usually the Addend is read out of the instruction and the relocation entry points to the instruction. The PE/COFF spec is pending an update to describe ARM MOVW & MOVT relocation types.
Modified Paths:
--------------
trunk/BaseTools/Source/C/Common/BasePeCoff.c
trunk/BaseTools/Source/C/Common/PeCoffLib.h
trunk/BaseTools/Source/C/Common/PeCoffLoaderEx.c
trunk/BaseTools/Source/C/GenFw/GenFw.c
trunk/BaseTools/Source/C/GenFw/elf_common.h
trunk/BaseTools/Source/C/Include/Common/BaseTypes.h
trunk/BaseTools/Source/C/Include/IndustryStandard/PeImage.h
Modified: trunk/BaseTools/Source/C/Common/BasePeCoff.c
===================================================================
--- trunk/BaseTools/Source/C/Common/BasePeCoff.c 2010-03-23 09:18:48 UTC (rev 1940)
+++ trunk/BaseTools/Source/C/Common/BasePeCoff.c 2010-03-24 17:29:20 UTC (rev 1941)
@@ -71,6 +71,14 @@
IN UINT64 Adjust
);
+RETURN_STATUS
+PeCoffLoaderRelocateArmImage (
+ IN UINT16 **Reloc,
+ IN OUT CHAR8 *Fixup,
+ IN OUT CHAR8 **FixupData,
+ IN UINT64 Adjust
+ );
+
STATIC
RETURN_STATUS
PeCoffLoaderGetPeHeader (
@@ -777,9 +785,11 @@
default:
switch (MachineType) {
case EFI_IMAGE_MACHINE_IA32:
- case EFI_IMAGE_MACHINE_ARMT:
Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust);
break;
+ case EFI_IMAGE_MACHINE_ARMT:
+ Status = PeCoffLoaderRelocateArmImage (&Reloc, Fixup, &FixupData, Adjust);
+ break;
case EFI_IMAGE_MACHINE_X64:
Status = PeCoffLoaderRelocateX64Image (Reloc, Fixup, &FixupData, Adjust);
break;
Modified: trunk/BaseTools/Source/C/Common/PeCoffLib.h
===================================================================
--- trunk/BaseTools/Source/C/Common/PeCoffLib.h 2010-03-23 09:18:48 UTC (rev 1940)
+++ trunk/BaseTools/Source/C/Common/PeCoffLib.h 2010-03-24 17:29:20 UTC (rev 1941)
@@ -144,4 +144,38 @@
)
;
+//
+// These functions are used by the ARM PE/COFF relocation code and by
+// the ELF to PE/COFF converter so that is why they are public
+//
+
+/**
+ Pass in a pointer to an ARM MOVT or MOVW immediate instruciton and
+ return the immediate data encoded in the instruction
+
+ @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
+
+ @return Immediate address encoded in the instruction
+
+**/
+UINT16
+ThumbMovtImmediateAddress (
+ IN UINT16 *Instruction
+ );
+
+/**
+ Update an ARM MOVT or MOVW immediate instruction immediate data.
+
+ @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
+ @param Address New addres to patch into the instruction
+
+**/
+VOID
+ThumbMovtImmediatePatch (
+ IN OUT UINT16 *Instruction,
+ IN UINT16 Address
+ );
+
+
+
#endif
Modified: trunk/BaseTools/Source/C/Common/PeCoffLoaderEx.c
===================================================================
--- trunk/BaseTools/Source/C/Common/PeCoffLoaderEx.c 2010-03-23 09:18:48 UTC (rev 1940)
+++ trunk/BaseTools/Source/C/Common/PeCoffLoaderEx.c 2010-03-24 17:29:20 UTC (rev 1941)
@@ -315,3 +315,121 @@
return RETURN_SUCCESS;
}
+/**
+ Pass in a pointer to an ARM MOVT or MOVW immediate instruciton and
+ return the immediate data encoded in the instruction
+
+ @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
+
+ @return Immediate address encoded in the instruction
+
+**/
+UINT16
+ThumbMovtImmediateAddress (
+ IN UINT16 *Instruction
+ )
+{
+ UINT32 Movt;
+ UINT16 Address;
+
+ // Thumb2 is two 16-bit instructions working together. Not a single 32-bit instruction
+ // Example MOVT R0, #0 is 0x0000f2c0 or 0xf2c0 0x0000
+ Movt = (*Instruction << 16) | (*(Instruction + 1));
+
+ // imm16 = imm4:i:imm3:imm8
+ // imm4 -> Bit19:Bit16
+ // i -> Bit26
+ // imm3 -> Bit14:Bit12
+ // imm8 -> Bit7:Bit0
+ Address = (UINT16)(Movt & 0x000000ff); // imm8
+ Address |= (UINT16)((Movt >> 4) & 0x0000f700); // imm4 imm3
+ Address |= (((Movt & BIT26) != 0) ? BIT11 : 0); // i
+ return Address;
+}
+
+
+/**
+ Update an ARM MOVT or MOVW immediate instruction immediate data.
+
+ @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
+ @param Address New addres to patch into the instruction
+**/
+VOID
+ThumbMovtImmediatePatch (
+ IN OUT UINT16 *Instruction,
+ IN UINT16 Address
+ )
+{
+ UINT16 Patch;
+
+ // First 16-bit chunk of instruciton
+ Patch = ((Address >> 12) & 0x000f); // imm4
+ Patch |= (((Address & BIT11) != 0) ? BIT10 : 0); // i
+ *Instruction = (*Instruction & ~0x040f) | Patch;
+
+ // Second 16-bit chunk of instruction
+ Patch = Address & 0x000000ff; // imm8
+ Patch |= ((Address << 4) & 0x00007000); // imm3
+ Instruction++;
+ *Instruction = (*Instruction & ~0x70ff) | Patch;
+}
+
+/**
+ Performs an ARM-based specific relocation fixup and is a no-op on other
+ instruction sets.
+
+ @param Reloc Pointer to the relocation record.
+ @param Fixup Pointer to the address to fix up.
+ @param FixupData Pointer to a buffer to log the fixups.
+ @param Adjust The offset to adjust the fixup.
+
+ @return Status code.
+
+**/
+RETURN_STATUS
+PeCoffLoaderRelocateArmImage (
+ IN UINT16 **Reloc,
+ IN OUT CHAR8 *Fixup,
+ IN OUT CHAR8 **FixupData,
+ IN UINT64 Adjust
+ )
+{
+ UINT16 *Fixup16;
+ UINT16 FixupVal;
+ UINT16 *Addend;
+
+ Fixup16 = (UINT16 *) Fixup;
+
+ switch ((**Reloc) >> 12) {
+ case EFI_IMAGE_REL_BASED_ARM_THUMB_MOVW:
+ FixupVal = ThumbMovtImmediateAddress (Fixup16) + (UINT16)Adjust;
+ ThumbMovtImmediatePatch (Fixup16, FixupVal);
+
+ if (*FixupData != NULL) {
+ *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT16));
+ *(UINT16 *)*FixupData = *Fixup16;
+ *FixupData = *FixupData + sizeof (UINT16);
+ }
+ break;
+
+ case EFI_IMAGE_REL_BASED_ARM_THUMB_MOVT:
+ // For MOVT you need to know the lower 16-bits do do the math
+ // So this relocation entry is really two entries.
+ *Reloc = *Reloc + 1;
+ Addend = *Reloc;
+ FixupVal = (UINT16)(((ThumbMovtImmediateAddress (Fixup16) << 16) + Adjust + *Addend) >> 16);
+ ThumbMovtImmediatePatch (Fixup16, FixupVal);
+
+ if (*FixupData != NULL) {
+ *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT16));
+ *(UINT16 *)*FixupData = *Fixup16;
+ *FixupData = *FixupData + sizeof (UINT16);
+ }
+ break;
+
+ default:
+ return RETURN_UNSUPPORTED;
+ }
+
+ return RETURN_SUCCESS;
+}
Modified: trunk/BaseTools/Source/C/GenFw/GenFw.c
===================================================================
--- trunk/BaseTools/Source/C/GenFw/GenFw.c 2010-03-23 09:18:48 UTC (rev 1940)
+++ trunk/BaseTools/Source/C/GenFw/GenFw.c 2010-03-24 17:29:20 UTC (rev 1941)
@@ -988,8 +988,9 @@
//
for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
- if (RelShdr->sh_type != SHT_REL)
+ if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {
continue;
+ }
SecShdr = GetShdrByIndex(RelShdr->sh_info);
SecOffset = CoffSectionsOffset[RelShdr->sh_info];
if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
@@ -1002,6 +1003,7 @@
Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
Elf_Shdr *SymShdr;
UINT8 *Targ;
+ UINT16 Address;
if (Sym->st_shndx == SHN_UNDEF
|| Sym->st_shndx == SHN_ABS
@@ -1040,16 +1042,31 @@
}
} else if (Ehdr->e_machine == EM_ARM) {
switch (ELF32_R_TYPE(Rel->r_info)) {
- case R_ARM_RBASE: // No relocation - no action required
+ case R_ARM_RBASE:
+ // No relocation - no action required
- // Thease are all PC-relative relocations and don't require modification
case R_ARM_PC24:
case R_ARM_XPC25:
case R_ARM_THM_PC22:
case R_ARM_THM_JUMP19:
case R_ARM_CALL:
+ case R_ARM_JMP24:
+ // Thease are all PC-relative relocations and don't require modification
+ // GCC does not seem to have the concept of a application that just needs to get relocated.
break;
+
+ case R_ARM_THM_MOVW_ABS_NC:
+ // MOVW is only lower 16-bits of the addres
+ Address = (UINT16)(Sym->st_value - SymShdr->sh_addr + CoffSectionsOffset[Sym->st_shndx]);
+ ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
+ break;
+ case R_ARM_THM_MOVT_ABS:
+ // MOVT is only upper 16-bits of the addres
+ Address = (UINT16)((Sym->st_value - SymShdr->sh_addr + CoffSectionsOffset[Sym->st_shndx]) >> 16);
+ ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
+ break;
+
case R_ARM_ABS32:
case R_ARM_RABS32:
//
@@ -1057,6 +1074,7 @@
//
*(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr + CoffSectionsOffset[Sym->st_shndx];
break;
+
default:
Error (NULL, 0, 3000, "Invalid", "WriteSections (): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));
}
@@ -1149,17 +1167,27 @@
UINT8 *Targ;
Elf32_Phdr *DynamicSegment;
Elf32_Phdr *TargetSegment;
+ Elf_Sym *Sym;
+ Elf_Shdr *SymtabShdr;
+ UINT8 *Symtab;
+
for (Index = 0, FoundRelocations = FALSE; Index < Ehdr->e_shnum; Index++) {
Elf_Shdr *RelShdr = GetShdrByIndex(Index);
- if (RelShdr->sh_type == SHT_REL) {
- Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
+ if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {
+ Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);
if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
UINT32 RelIdx;
+
+ SymtabShdr = GetShdrByIndex (RelShdr->sh_link);
+ Symtab = (UINT8*)Ehdr + SymtabShdr->sh_offset;
FoundRelocations = TRUE;
for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
- Elf_Rel *Rel = (Elf_Rel *)
- ((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
+ Elf_Rel *Rel = (Elf_Rel *)((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
+ Elf_Shdr *SymShdr;
+
+ Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
+ SymShdr = GetShdrByIndex (Sym->st_shndx);
if (Ehdr->e_machine == EM_386) {
switch (ELF_R_TYPE(Rel->r_info)) {
@@ -1176,15 +1204,36 @@
}
} else if (Ehdr->e_machine == EM_ARM) {
switch (ELF32_R_TYPE(Rel->r_info)) {
- case R_ARM_RBASE: // No relocation - no action required
-
- // Thease are all PC-relative relocations and don't require modification
+ case R_ARM_RBASE:
+ // No relocation - no action required
case R_ARM_PC24:
case R_ARM_XPC25:
case R_ARM_THM_PC22:
case R_ARM_THM_JUMP19:
case R_ARM_CALL:
+ case R_ARM_JMP24:
+ // Thease are all PC-relative relocations and don't require modification
break;
+
+ case R_ARM_THM_MOVW_ABS_NC:
+ CoffAddFixup (
+ CoffSectionsOffset[RelShdr->sh_info]
+ + (Rel->r_offset - SecShdr->sh_addr),
+ EFI_IMAGE_REL_BASED_ARM_THUMB_MOVW
+ );
+ break;
+
+ case R_ARM_THM_MOVT_ABS:
+ CoffAddFixup (
+ CoffSectionsOffset[RelShdr->sh_info]
+ + (Rel->r_offset - SecShdr->sh_addr),
+ EFI_IMAGE_REL_BASED_ARM_THUMB_MOVT
+ );
+
+ // The relocation entry needs to contain the lower 16-bits so we can do math
+ CoffAddFixupEntry ((UINT16)(Sym->st_value - SymShdr->sh_addr + CoffSectionsOffset[Sym->st_shndx]));
+ break;
+
case R_ARM_ABS32:
case R_ARM_RABS32:
CoffAddFixup (
@@ -1241,6 +1290,7 @@
Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName);
}
+
for (K = 0; K < RelSize; K += RelElementSize) {
if (DynamicSegment->p_paddr == 0) {
@@ -1254,6 +1304,7 @@
switch (ELF32_R_TYPE (Rel->r_info)) {
case R_ARM_RBASE:
break;
+
case R_ARM_RABS32:
TargetSegment = GetPhdrByIndex (ELF32_R_SYM (Rel->r_info) - 1);
@@ -1264,6 +1315,7 @@
CoffAddFixup (CoffSectionsOffset[ELF32_R_SYM (Rel->r_info)] + (Rel->r_offset - TargetSegment->p_vaddr), EFI_IMAGE_REL_BASED_HIGHLOW);
break;
+
default:
Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations, unkown type %d.", mInImageName, ELF32_R_TYPE (Rel->r_info));
break;
Modified: trunk/BaseTools/Source/C/GenFw/elf_common.h
===================================================================
--- trunk/BaseTools/Source/C/GenFw/elf_common.h 2010-03-23 09:18:48 UTC (rev 1940)
+++ trunk/BaseTools/Source/C/GenFw/elf_common.h 2010-03-24 17:29:20 UTC (rev 1941)
@@ -597,7 +597,11 @@
#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */
#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */
#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */
-#define R_ARM_CALL 28
+#define R_ARM_CALL 28
+#define R_ARM_JMP24 29
+#define R_ARM_THM_MOVW_ABS_NC 47
+#define R_ARM_THM_MOVT_ABS 48
+
#define R_ARM_THM_JUMP19 51
#define R_ARM_GNU_VTENTRY 100
#define R_ARM_GNU_VTINHERIT 101
Modified: trunk/BaseTools/Source/C/Include/Common/BaseTypes.h
===================================================================
--- trunk/BaseTools/Source/C/Include/Common/BaseTypes.h 2010-03-23 09:18:48 UTC (rev 1940)
+++ trunk/BaseTools/Source/C/Include/Common/BaseTypes.h 2010-03-24 17:29:20 UTC (rev 1941)
@@ -220,4 +220,69 @@
typedef UINT64 PHYSICAL_ADDRESS;
+#define BIT0 0x00000001
+#define BIT1 0x00000002
+#define BIT2 0x00000004
+#define BIT3 0x00000008
+#define BIT4 0x00000010
+#define BIT5 0x00000020
+#define BIT6 0x00000040
+#define BIT7 0x00000080
+#define BIT8 0x00000100
+#define BIT9 0x00000200
+#define BIT10 0x00000400
+#define BIT11 0x00000800
+#define BIT12 0x00001000
+#define BIT13 0x00002000
+#define BIT14 0x00004000
+#define BIT15 0x00008000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+#define BIT32 0x0000000100000000ULL
+#define BIT33 0x0000000200000000ULL
+#define BIT34 0x0000000400000000ULL
+#define BIT35 0x0000000800000000ULL
+#define BIT36 0x0000001000000000ULL
+#define BIT37 0x0000002000000000ULL
+#define BIT38 0x0000004000000000ULL
+#define BIT39 0x0000008000000000ULL
+#define BIT40 0x0000010000000000ULL
+#define BIT41 0x0000020000000000ULL
+#define BIT42 0x0000040000000000ULL
+#define BIT43 0x0000080000000000ULL
+#define BIT44 0x0000100000000000ULL
+#define BIT45 0x0000200000000000ULL
+#define BIT46 0x0000400000000000ULL
+#define BIT47 0x0000800000000000ULL
+#define BIT48 0x0001000000000000ULL
+#define BIT49 0x0002000000000000ULL
+#define BIT50 0x0004000000000000ULL
+#define BIT51 0x0008000000000000ULL
+#define BIT52 0x0010000000000000ULL
+#define BIT53 0x0020000000000000ULL
+#define BIT54 0x0040000000000000ULL
+#define BIT55 0x0080000000000000ULL
+#define BIT56 0x0100000000000000ULL
+#define BIT57 0x0200000000000000ULL
+#define BIT58 0x0400000000000000ULL
+#define BIT59 0x0800000000000000ULL
+#define BIT60 0x1000000000000000ULL
+#define BIT61 0x2000000000000000ULL
+#define BIT62 0x4000000000000000ULL
+#define BIT63 0x8000000000000000ULL
+
#endif
Modified: trunk/BaseTools/Source/C/Include/IndustryStandard/PeImage.h
===================================================================
--- trunk/BaseTools/Source/C/Include/IndustryStandard/PeImage.h 2010-03-23 09:18:48 UTC (rev 1940)
+++ trunk/BaseTools/Source/C/Include/IndustryStandard/PeImage.h 2010-03-24 17:29:20 UTC (rev 1941)
@@ -513,6 +513,9 @@
#define EFI_IMAGE_REL_BASED_IA64_IMM64 9
#define EFI_IMAGE_REL_BASED_DIR64 10
+#define EFI_IMAGE_REL_BASED_ARM_THUMB_MOVW 11
+#define EFI_IMAGE_REL_BASED_ARM_THUMB_MOVT 12
+
///
/// Line number format.
///
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|