Discussion:
[edk2] [PATCH] BaseTools/GenFw: Added AArch64 page-relative relocations
Olivier Martin
2015-07-08 14:57:22 UTC
Permalink
When EDK2 is built for the small memory model with AArch64 LLVM,
some page-relative relocations (R_AARCH64_ADR_PREL_PG_HI21 and its
R_AARCH64_LDST(16|32|64|128)_ABS_LO12_NC companions) that were not
supported before by EDK2 BaseTools are now needed.

This change adds support for these relocations in BaseTools.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Harry Liebel <***@arm.com>
Reviewed-by: Olivier Martin <***@arm.com>
---
BaseTools/Source/C/Common/BasePeCoff.c | 14 +++
BaseTools/Source/C/Common/PeCoffLib.h | 13 +++
BaseTools/Source/C/Common/PeCoffLoaderEx.c | 58 +++++++++++
BaseTools/Source/C/GenFw/Elf64Convert.c | 159 +++++++++++++++++++++++------
BaseTools/Source/C/GenFw/elf_common.h | 4 +
5 files changed, 215 insertions(+), 33 deletions(-)

diff --git a/BaseTools/Source/C/Common/BasePeCoff.c b/BaseTools/Source/C/Common/BasePeCoff.c
index afb45df..e1401f2 100644
--- a/BaseTools/Source/C/Common/BasePeCoff.c
+++ b/BaseTools/Source/C/Common/BasePeCoff.c
@@ -715,6 +715,20 @@ Returns:
RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
}

+ // In order for page relative code relocations to work on AArch64 we need to
+ // ensure that any address adjustment to images are 4k page aligned. The page
+ // relative relocations are processed at build time as we do not have enough
+ // information at runtime to recalculate them.
+ // The PE/COFF Base relocation types do not have a matching type to describe
+ // page relative relocations so we do not know if they may be present in the
+ // images. We must assume they are present and ensure the image is properly
+ // aligned to keep these relocations valid.
+ if (ImageContext->Machine == EFI_IMAGE_MACHINE_AARCH64) {
+ if ((Adjust & 0xfff) != 0x0) {
+ return RETURN_LOAD_ERROR;
+ }
+ }
+
//
// Run the relocation information and apply the fixups
//
diff --git a/BaseTools/Source/C/Common/PeCoffLib.h b/BaseTools/Source/C/Common/PeCoffLib.h
index b56dd75..2f8feb7 100644
--- a/BaseTools/Source/C/Common/PeCoffLib.h
+++ b/BaseTools/Source/C/Common/PeCoffLib.h
@@ -205,6 +205,19 @@ ThumbMovwMovtImmediatePatch (
IN UINT32 Address
);

+/**
+ Update AArch64 instruction immediate address data.
+
+ @param Instruction Pointer to AArch64 instruction to update
+ @param Address New addres to patch into the instruction
+
+**/
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Val
+ );


#endif
diff --git a/BaseTools/Source/C/Common/PeCoffLoaderEx.c b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
index b7b7227..3864391 100644
--- a/BaseTools/Source/C/Common/PeCoffLoaderEx.c
+++ b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
@@ -466,6 +466,64 @@ PeCoffLoaderRelocateArmImage (
return RETURN_SUCCESS;
}

+
+/**
+ Update AArch64 instruction immediate address data.
+
+ @param Instruction Pointer to AArch64 instruction to update
+ @param Value New value to patch into the instruction. Signed value
+ to preserve sign extension where needed. Some
+ instructions can have positive and negative values.
+
+**/
+// The values below are used to match instructions based on the architecture encoding
+// Don't support shifted imm12 for ADD instructions. Set as 0 in MASK and INST
+#define AARCH64_ADD_MASK 0x1FC00000
+#define AARCH64_ADD_INST 0x11000000
+#define AARCH64_ADD_IMM 0x003FFC00
+#define IS_AARCH64_ADD(x) ((x & AARCH64_ADD_MASK) == AARCH64_ADD_INST)
+#define AARCH64_ADRP_MASK 0x9f000000
+#define AARCH64_ADRP_INST 0x90000000
+#define AARCH64_ADRP_IMM 0x60FFFFE0
+#define IS_AARCH64_ADRP(x) ((x & AARCH64_ADRP_MASK) == AARCH64_ADRP_INST)
+#define AARCH64_LDST_MASK 0x3b000000
+#define AARCH64_LDST_INST 0x39000000
+#define AARCH64_LDST_IMM 0x003FFC00
+#define IS_AARCH64_LDST(x) ((x & AARCH64_LDST_MASK) == AARCH64_LDST_INST)
+
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Value
+ )
+{
+ UINT32 Patch;
+ RETURN_STATUS Status;
+
+ Status = RETURN_UNSUPPORTED;
+
+ // Disassemble and update the instruction
+ if (IS_AARCH64_ADD (*Instruction)) {
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_ADD_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_ADRP (*Instruction)) {
+ Patch = ((Value & 0x3) << 29) | (((Value & 0x1FFFFC) >> 2) << 5);
+ *Instruction = (*Instruction & ~AARCH64_ADRP_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_LDST (*Instruction)) {
+ // Relocation types LDST8,16,32,64,128 specify different bitsizes.
+ // The Calling function knows the relocation type and has already masked and
+ // scaled the address as needed.
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_LDST_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ }
+
+ return Status;
+}
+
RETURN_STATUS
PeCoffLoaderRelocateAArch64Image (
IN UINT16 *Reloc,
diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c b/BaseTools/Source/C/GenFw/Elf64Convert.c
index d2becf1..355398f 100644
--- a/BaseTools/Source/C/GenFw/Elf64Convert.c
+++ b/BaseTools/Source/C/GenFw/Elf64Convert.c
@@ -709,56 +709,148 @@ WriteSections64 (
Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
}
} else if (mEhdr->e_machine == EM_AARCH64) {
-
- // AARCH64 GCC uses RELA relocation, so all relocations have to be fixed up.
- // As opposed to ARM32 using REL.
-
+ // For ease of use specify relocations in terms of P, S and A as
+ // described the AArch64 ELF specification
+ UINT64 P, S;
+ INT64 A;
+ RETURN_STATUS Status;
+
+ // P - Address of the 'Place' being relocated
+ // S - Address of the Symbol
+ // A - The Addend for the relocation
+ P = (UINT64)(SecOffset + (Rel->r_offset - SecShdr->sh_addr));
+ S = (UINT64)(Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);
+ A = (INT64)(Rel->r_addend);
+
+ // Some versions of the AArch64 GCC linker does not update the ELF
+ // relocations properly when doing the final static link. For this
+ // reason we do not fully recalculate the relocations that it might
+ // use with the Large memory model. We rely on the assumption that the
+ // code sections affected by these relocations are not reordered going
+ // from ELF to PE/COFF and a simple offset adjustment is sufficient.
+ // In the case of the ARM LLVM based compiler the relocation
+ // information is correct and as such we can use the small memory
+ // model and recalculate the relocations based on 'Place', 'Symbol'
+ // and 'Addend' information. At some point in the future this should
+ // be be done for AArch64 GCC as well.
switch (ELF_R_TYPE(Rel->r_info)) {

+ // Ideally we should recalculate all relocations in case the code
+ // sections moved around, but in some AArch64 GCC versions this is
+ // currently not working correctly.
+
+ // Relative relocations
case R_AARCH64_ADR_PREL_LO21:
- if (Rel->r_addend != 0 ) { /* TODO */
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_ADR_PREL_LO21 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_ADR_PREL_LO21: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;

case R_AARCH64_CONDBR19:
- if (Rel->r_addend != 0 ) { /* TODO */
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_CONDBR19 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CONDBR19: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;

case R_AARCH64_LD_PREL_LO19:
- if (Rel->r_addend != 0 ) { /* TODO */
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_LD_PREL_LO19 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_LD_PREL_LO19: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;

case R_AARCH64_CALL26:
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CALL26: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ break;
+
case R_AARCH64_JUMP26:
- if (Rel->r_addend != 0 ) {
- // Some references to static functions sometime start at the base of .text + addend.
- // It is safe to ignore these relocations because they patch a `BL` instructions that
- // contains an offset from the instruction itself and there is only a single .text section.
- // So we check if the symbol is a "section symbol"
- if (ELF64_ST_TYPE (Sym->st_info) == STT_SECTION) {
- break;
- }
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_JUMP26: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;

case R_AARCH64_ADR_PREL_PG_HI21:
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);
+ // We need to fully recalculate this relocation. This is used with the small memory model.
+ // Reloc = PAGE(S+A) - PAGE(P) ; Page = 4k
+ VerboseMsg ("R_AARCH64_ADR_PREL_PG_HI21: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ INT32 Tmp = R_AARCH64_PAGE (S + A) - R_AARCH64_PAGE (P);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, Tmp / 4096);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
break;

case R_AARCH64_ADD_ABS_LO12_NC:
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ADD_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) & R_AARCH64_PAGE_MASK);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST8_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) & R_AARCH64_PAGE_MASK);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST16_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) & R_AARCH64_PAGE_MASK) >> 1 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST32_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) & R_AARCH64_PAGE_MASK) >> 2 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST64_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) & R_AARCH64_PAGE_MASK) >> 3 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST128_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) & R_AARCH64_PAGE_MASK) >> 4 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
break;

// Absolute relocations.
case R_AARCH64_ABS64:
+ // GCC with Large memory model uses this one. Don't recalculate the
+ // relocation, just do the section offset adjustment. This assumes
+ // the relevant sections are not getting reordered.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ABS64: Targ = 0x%08lx, *Targ=0x%08lx\n", (UINT64)Targ, *(UINT64 *)Targ);
+
+ // If S lives in bss (like global gST):
+ // *Targ = *Targ - elf-section-addr[bss] + coff-section-addr[bss]
*(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];
break;

@@ -838,17 +930,18 @@ WriteRelocations64 (
case R_AARCH64_JUMP26:
break;

+ // These relocations are used together
case R_AARCH64_ADR_PREL_PG_HI21:
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);
- break;
-
case R_AARCH64_ADD_ABS_LO12_NC:
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ case R_AARCH64_LDST128_ABS_LO12_NC:
break;

case R_AARCH64_ABS64:
+ // Write DIR64 to the PE/COFF reloc fixup list
CoffAddFixup(
(UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]
+ (Rel->r_offset - SecShdr->sh_addr)),
diff --git a/BaseTools/Source/C/GenFw/elf_common.h b/BaseTools/Source/C/GenFw/elf_common.h
index 766d0e4..d9057b6 100644
--- a/BaseTools/Source/C/GenFw/elf_common.h
+++ b/BaseTools/Source/C/GenFw/elf_common.h
@@ -673,6 +673,10 @@ typedef struct {
#define R_AARCH64_TLS_DTPREL32 1031 /* DTPREL(S+A) */
#define R_AARCH64_TLS_DTPMOD32 1032 /* LDM(S) */
#define R_AARCH64_TLS_TPREL32 1033 /* DTPREL(S+A) */
+/* AArch64 page relative relocations use 4k pages. */
+#define R_AARCH64_PAGE_SIZE 0x1000
+#define R_AARCH64_PAGE_MASK 0xfffUL
+#define R_AARCH64_PAGE(x) ((x) & ~R_AARCH64_PAGE_MASK)

#define R_ALPHA_NONE 0 /* No reloc */
#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
--
2.1.1
Ard Biesheuvel
2015-07-08 17:49:34 UTC
Permalink
Post by Olivier Martin
When EDK2 is built for the small memory model with AArch64 LLVM,
some page-relative relocations (R_AARCH64_ADR_PREL_PG_HI21 and its
R_AARCH64_LDST(16|32|64|128)_ABS_LO12_NC companions) that were not
supported before by EDK2 BaseTools are now needed.
This change adds support for these relocations in BaseTools.
Contributed-under: TianoCore Contribution Agreement 1.0
I think all the relocation arithmetic looks fine.

I do have a concern about the consequences of using the small C model
in this way: nothing in the metadata of the resulting PE/COFF images
reflects that the 4 KB alignment needs to be preserved in order to
successfully execute them, so you are essentially producing corrupt
images. Every PE/COFF loader needs to be modified (including the ones
in GRUB and shim, for instance) to prevent such images from being
loaded in an incorrect way. (I know that most PE/COFF loaders use
AllocatePages() which aligns these binaries at 4 KB implicitly, but
this is not mandatory)

So the correct way to do this would be to only use the small C model
when this alignment can be guaranteed, i.e., .text and .data are both
aligned at 4 KB. With the latest GenFw changes in place (which sets
PE/COFF section alignment to the largest ELF input section alignment
it encounters), the small C model works correctly since the PE/COFF
loaders adhere to the PE/COFF section alignment. As a bonus, the ELF
and PE/COFF images will be laid out identically in memory, so all the
recalculation arithmetic becomes unnecessary (although it probably
makes sense to perform some checks here)

The downside, of course, is that 4 KB alignment for both .text and
.data wastes a lot of space: 3.5 KB only for the padding between the
PE/COFF header and the start of .text, and 2 KB on average between
.text and .data. Due to the compression of non-XIP binaries, this is
not such a penalty, but for XIP it is prohibitive (even if these
typically don't have a .data section)

I am going to have a look at GenFv to figure out if there is some way
to work around this, i.e., drop the PE/COFF headers or move them in
some way.

In the mean time, I think this patch is good except the first hunk.
The small model relocation arithmetic can be merged separately, I
think, and the logic and policies around how and when to relocate
PE/COFF images can be addressed in a followup patch.
--
Ard.
Post by Olivier Martin
---
BaseTools/Source/C/Common/BasePeCoff.c | 14 +++
BaseTools/Source/C/Common/PeCoffLib.h | 13 +++
BaseTools/Source/C/Common/PeCoffLoaderEx.c | 58 +++++++++++
BaseTools/Source/C/GenFw/Elf64Convert.c | 159 +++++++++++++++++++++++------
BaseTools/Source/C/GenFw/elf_common.h | 4 +
5 files changed, 215 insertions(+), 33 deletions(-)
diff --git a/BaseTools/Source/C/Common/BasePeCoff.c b/BaseTools/Source/C/Common/BasePeCoff.c
index afb45df..e1401f2 100644
--- a/BaseTools/Source/C/Common/BasePeCoff.c
+++ b/BaseTools/Source/C/Common/BasePeCoff.c
RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
}
+ // In order for page relative code relocations to work on AArch64 we need to
+ // ensure that any address adjustment to images are 4k page aligned. The page
+ // relative relocations are processed at build time as we do not have enough
+ // information at runtime to recalculate them.
+ // The PE/COFF Base relocation types do not have a matching type to describe
+ // page relative relocations so we do not know if they may be present in the
+ // images. We must assume they are present and ensure the image is properly
+ // aligned to keep these relocations valid.
+ if (ImageContext->Machine == EFI_IMAGE_MACHINE_AARCH64) {
+ if ((Adjust & 0xfff) != 0x0) {
+ return RETURN_LOAD_ERROR;
+ }
+ }
+
//
// Run the relocation information and apply the fixups
//
diff --git a/BaseTools/Source/C/Common/PeCoffLib.h b/BaseTools/Source/C/Common/PeCoffLib.h
index b56dd75..2f8feb7 100644
--- a/BaseTools/Source/C/Common/PeCoffLib.h
+++ b/BaseTools/Source/C/Common/PeCoffLib.h
@@ -205,6 +205,19 @@ ThumbMovwMovtImmediatePatch (
IN UINT32 Address
);
+/**
+ Update AArch64 instruction immediate address data.
+
+
+**/
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Val
+ );
#endif
diff --git a/BaseTools/Source/C/Common/PeCoffLoaderEx.c b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
index b7b7227..3864391 100644
--- a/BaseTools/Source/C/Common/PeCoffLoaderEx.c
+++ b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
@@ -466,6 +466,64 @@ PeCoffLoaderRelocateArmImage (
return RETURN_SUCCESS;
}
+
+/**
+ Update AArch64 instruction immediate address data.
+
+ to preserve sign extension where needed. Some
+ instructions can have positive and negative values.
+
+**/
+// The values below are used to match instructions based on the architecture encoding
+// Don't support shifted imm12 for ADD instructions. Set as 0 in MASK and INST
+#define AARCH64_ADD_MASK 0x1FC00000
+#define AARCH64_ADD_INST 0x11000000
+#define AARCH64_ADD_IMM 0x003FFC00
+#define IS_AARCH64_ADD(x) ((x & AARCH64_ADD_MASK) == AARCH64_ADD_INST)
+#define AARCH64_ADRP_MASK 0x9f000000
+#define AARCH64_ADRP_INST 0x90000000
+#define AARCH64_ADRP_IMM 0x60FFFFE0
+#define IS_AARCH64_ADRP(x) ((x & AARCH64_ADRP_MASK) == AARCH64_ADRP_INST)
+#define AARCH64_LDST_MASK 0x3b000000
+#define AARCH64_LDST_INST 0x39000000
+#define AARCH64_LDST_IMM 0x003FFC00
+#define IS_AARCH64_LDST(x) ((x & AARCH64_LDST_MASK) == AARCH64_LDST_INST)
+
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Value
+ )
+{
+ UINT32 Patch;
+ RETURN_STATUS Status;
+
+ Status = RETURN_UNSUPPORTED;
+
+ // Disassemble and update the instruction
+ if (IS_AARCH64_ADD (*Instruction)) {
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_ADD_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_ADRP (*Instruction)) {
+ Patch = ((Value & 0x3) << 29) | (((Value & 0x1FFFFC) >> 2) << 5);
+ *Instruction = (*Instruction & ~AARCH64_ADRP_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_LDST (*Instruction)) {
+ // Relocation types LDST8,16,32,64,128 specify different bitsizes.
+ // The Calling function knows the relocation type and has already masked and
+ // scaled the address as needed.
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_LDST_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ }
+
+ return Status;
+}
+
RETURN_STATUS
PeCoffLoaderRelocateAArch64Image (
IN UINT16 *Reloc,
diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c b/BaseTools/Source/C/GenFw/Elf64Convert.c
index d2becf1..355398f 100644
--- a/BaseTools/Source/C/GenFw/Elf64Convert.c
+++ b/BaseTools/Source/C/GenFw/Elf64Convert.c
@@ -709,56 +709,148 @@ WriteSections64 (
Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
}
} else if (mEhdr->e_machine == EM_AARCH64) {
-
- // AARCH64 GCC uses RELA relocation, so all relocations have to be fixed up.
- // As opposed to ARM32 using REL.
-
+ // For ease of use specify relocations in terms of P, S and A as
+ // described the AArch64 ELF specification
+ UINT64 P, S;
+ INT64 A;
+ RETURN_STATUS Status;
+
+ // P - Address of the 'Place' being relocated
+ // S - Address of the Symbol
+ // A - The Addend for the relocation
+ P = (UINT64)(SecOffset + (Rel->r_offset - SecShdr->sh_addr));
+ S = (UINT64)(Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);
+ A = (INT64)(Rel->r_addend);
+
+ // Some versions of the AArch64 GCC linker does not update the ELF
+ // relocations properly when doing the final static link. For this
+ // reason we do not fully recalculate the relocations that it might
+ // use with the Large memory model. We rely on the assumption that the
+ // code sections affected by these relocations are not reordered going
+ // from ELF to PE/COFF and a simple offset adjustment is sufficient.
+ // In the case of the ARM LLVM based compiler the relocation
+ // information is correct and as such we can use the small memory
+ // model and recalculate the relocations based on 'Place', 'Symbol'
+ // and 'Addend' information. At some point in the future this should
+ // be be done for AArch64 GCC as well.
switch (ELF_R_TYPE(Rel->r_info)) {
+ // Ideally we should recalculate all relocations in case the code
+ // sections moved around, but in some AArch64 GCC versions this is
+ // currently not working correctly.
+
+ // Relative relocations
- if (Rel->r_addend != 0 ) { /* TODO */
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_ADR_PREL_LO21 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_ADR_PREL_LO21: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
- if (Rel->r_addend != 0 ) { /* TODO */
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_CONDBR19 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CONDBR19: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
- if (Rel->r_addend != 0 ) { /* TODO */
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_LD_PREL_LO19 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_LD_PREL_LO19: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CALL26: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ break;
+
- if (Rel->r_addend != 0 ) {
- // Some references to static functions sometime start at the base of .text + addend.
- // It is safe to ignore these relocations because they patch a `BL` instructions that
- // contains an offset from the instruction itself and there is only a single .text section.
- // So we check if the symbol is a "section symbol"
- if (ELF64_ST_TYPE (Sym->st_info) == STT_SECTION) {
- break;
- }
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_JUMP26: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);
+ // We need to fully recalculate this relocation. This is used with the small memory model.
+ // Reloc = PAGE(S+A) - PAGE(P) ; Page = 4k
+ VerboseMsg ("R_AARCH64_ADR_PREL_PG_HI21: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ INT32 Tmp = R_AARCH64_PAGE (S + A) - R_AARCH64_PAGE (P);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, Tmp / 4096);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
break;
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ADD_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) & R_AARCH64_PAGE_MASK);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST8_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) & R_AARCH64_PAGE_MASK);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST16_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) & R_AARCH64_PAGE_MASK) >> 1 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST32_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) & R_AARCH64_PAGE_MASK) >> 2 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST64_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) & R_AARCH64_PAGE_MASK) >> 3 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST128_ABS_LO12_NC: Targ = 0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) & R_AARCH64_PAGE_MASK) >> 4 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF EM_AARCH64 relocation failed.", mInImageName);
+ }
break;
// Absolute relocations.
+ // GCC with Large memory model uses this one. Don't recalculate the
+ // relocation, just do the section offset adjustment. This assumes
+ // the relevant sections are not getting reordered.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ABS64: Targ = 0x%08lx, *Targ=0x%08lx\n", (UINT64)Targ, *(UINT64 *)Targ);
+
+ // *Targ = *Targ - elf-section-addr[bss] + coff-section-addr[bss]
*(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];
break;
@@ -838,17 +930,18 @@ WriteRelocations64 (
break;
+ // These relocations are used together
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);
- break;
-
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);
break;
+ // Write DIR64 to the PE/COFF reloc fixup list
CoffAddFixup(
(UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]
+ (Rel->r_offset - SecShdr->sh_addr)),
diff --git a/BaseTools/Source/C/GenFw/elf_common.h b/BaseTools/Source/C/GenFw/elf_common.h
index 766d0e4..d9057b6 100644
--- a/BaseTools/Source/C/GenFw/elf_common.h
+++ b/BaseTools/Source/C/GenFw/elf_common.h
@@ -673,6 +673,10 @@ typedef struct {
#define R_AARCH64_TLS_DTPREL32 1031 /* DTPREL(S+A) */
#define R_AARCH64_TLS_DTPMOD32 1032 /* LDM(S) */
#define R_AARCH64_TLS_TPREL32 1033 /* DTPREL(S+A) */
+/* AArch64 page relative relocations use 4k pages. */
+#define R_AARCH64_PAGE_SIZE 0x1000
+#define R_AARCH64_PAGE_MASK 0xfffUL
+#define R_AARCH64_PAGE(x) ((x) & ~R_AARCH64_PAGE_MASK)
#define R_ALPHA_NONE 0 /* No reloc */
#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
--
2.1.1
Andrew Fish
2015-07-08 18:01:12 UTC
Permalink
Post by Ard Biesheuvel
Post by Olivier Martin
When EDK2 is built for the small memory model with AArch64 LLVM,
some page-relative relocations (R_AARCH64_ADR_PREL_PG_HI21 and its
R_AARCH64_LDST(16|32|64|128)_ABS_LO12_NC companions) that were not
supported before by EDK2 BaseTools are now needed.
This change adds support for these relocations in BaseTools.
Contributed-under: TianoCore Contribution Agreement 1.0
I think all the relocation arithmetic looks fine.
I do have a concern about the consequences of using the small C model
in this way: nothing in the metadata of the resulting PE/COFF images
reflects that the 4 KB alignment needs to be preserved in order to
successfully execute them, so you are essentially producing corrupt
images.
Ard,

I’m missing something here. The PE/COFF header contains SectionAlignment and FileAlignment fields in the optional (for COFF, required for PE/COFF) headers?
SectionAlignment is the alignment of sections when copied to memory.
FileAlignment is the alignment in the PE/COFF file.

Thanks,

Andrew Fish
Post by Ard Biesheuvel
Every PE/COFF loader needs to be modified (including the ones
in GRUB and shim, for instance) to prevent such images from being
loaded in an incorrect way. (I know that most PE/COFF loaders use
AllocatePages() which aligns these binaries at 4 KB implicitly, but
this is not mandatory)
So the correct way to do this would be to only use the small C model
when this alignment can be guaranteed, i.e., .text and .data are both
aligned at 4 KB. With the latest GenFw changes in place (which sets
PE/COFF section alignment to the largest ELF input section alignment
it encounters), the small C model works correctly since the PE/COFF
loaders adhere to the PE/COFF section alignment. As a bonus, the ELF
and PE/COFF images will be laid out identically in memory, so all the
recalculation arithmetic becomes unnecessary (although it probably
makes sense to perform some checks here)
The downside, of course, is that 4 KB alignment for both .text and
.data wastes a lot of space: 3.5 KB only for the padding between the
PE/COFF header and the start of .text, and 2 KB on average between
.text and .data. Due to the compression of non-XIP binaries, this is
not such a penalty, but for XIP it is prohibitive (even if these
typically don't have a .data section)
I am going to have a look at GenFv to figure out if there is some way
to work around this, i.e., drop the PE/COFF headers or move them in
some way.
In the mean time, I think this patch is good except the first hunk.
The small model relocation arithmetic can be merged separately, I
think, and the logic and policies around how and when to relocate
PE/COFF images can be addressed in a followup patch.
--
Ard.
Ard Biesheuvel
2015-07-08 18:18:34 UTC
Permalink
Post by Olivier Martin
When EDK2 is built for the small memory model with AArch64 LLVM,
some page-relative relocations (R_AARCH64_ADR_PREL_PG_HI21 and its
R_AARCH64_LDST(16|32|64|128)_ABS_LO12_NC companions) that were not
supported before by EDK2 BaseTools are now needed.
This change adds support for these relocations in BaseTools.
Contributed-under: TianoCore Contribution Agreement 1.0
I think all the relocation arithmetic looks fine.
I do have a concern about the consequences of using the small C model
in this way: nothing in the metadata of the resulting PE/COFF images
reflects that the 4 KB alignment needs to be preserved in order to
successfully execute them, so you are essentially producing corrupt
images.
Ard,
I’m missing something here. The PE/COFF header contains SectionAlignment and
FileAlignment fields in the optional (for COFF, required for PE/COFF)
headers?
SectionAlignment is the alignment of sections when copied to memory.
FileAlignment is the alignment in the PE/COFF file.
Indeed. But unlike ELF, PE/COFF does not allow the header to overlap
with the .text section, so using 4 KB alignment for a XIP modules
.text section always wastes 3.5 KB in the FV.

Olivier's patch allows code to be generated that breaks if loaded at
an incorrect alignment, since adding the alignment required to prevent
such breakage results in the wasted space for XIP modules. Then it
fixes GenFv by making it aware that AARCH64 can only be adjusted
(relocated) by multiples of 4 KB even if the PE/COFF metadata
indicates nothing of the sort.

I would rather change GenFv so it can place the PE/COFF image in such
a way that the .text section meets its minimum alignment without
necessarily aligning the start of the image to the same value, either
by omitting the PE/COFF header entirely in the FV (if that is allowed
by the spec) or by moving the header closer to the .text section and
loading the image SIZEOF_HEADERS bytes before the alignment boundary.
That way, the section alignment correctly reflects the 4 KB value
required to support the small C model for AArch64.
--
Ard.
Post by Olivier Martin
Every PE/COFF loader needs to be modified (including the ones
in GRUB and shim, for instance) to prevent such images from being
loaded in an incorrect way. (I know that most PE/COFF loaders use
AllocatePages() which aligns these binaries at 4 KB implicitly, but
this is not mandatory)
So the correct way to do this would be to only use the small C model
when this alignment can be guaranteed, i.e., .text and .data are both
aligned at 4 KB. With the latest GenFw changes in place (which sets
PE/COFF section alignment to the largest ELF input section alignment
it encounters), the small C model works correctly since the PE/COFF
loaders adhere to the PE/COFF section alignment. As a bonus, the ELF
and PE/COFF images will be laid out identically in memory, so all the
recalculation arithmetic becomes unnecessary (although it probably
makes sense to perform some checks here)
The downside, of course, is that 4 KB alignment for both .text and
.data wastes a lot of space: 3.5 KB only for the padding between the
PE/COFF header and the start of .text, and 2 KB on average between
.text and .data. Due to the compression of non-XIP binaries, this is
not such a penalty, but for XIP it is prohibitive (even if these
typically don't have a .data section)
I am going to have a look at GenFv to figure out if there is some way
to work around this, i.e., drop the PE/COFF headers or move them in
some way.
In the mean time, I think this patch is good except the first hunk.
The small model relocation arithmetic can be merged separately, I
think, and the logic and policies around how and when to relocate
PE/COFF images can be addressed in a followup patch.
--
Ard.
------------------------------------------------------------------------------
Don't Limit Your Business. Reach for the Cloud.
GigeNET's Cloud Solutions provide you with the tools and support that
you need to offload your IT needs and focus on growing your business.
Configured For All Businesses. Start Your Cloud Today.
https://www.gigenetcloud.com/
_______________________________________________
edk2-devel mailing list
https://lists.sourceforge.net/lists/listinfo/edk2-devel
Andrew Fish
2015-07-08 18:48:33 UTC
Permalink
Post by Ard Biesheuvel
Indeed. But unlike ELF, PE/COFF does not allow the header to overlap
with the .text section, so using 4 KB alignment for a XIP modules
.text section always wastes 3.5 KB in the FV.
Olivier's patch allows code to be generated that breaks if loaded at
an incorrect alignment, since adding the alignment required to prevent
such breakage results in the wasted space for XIP modules. Then it
fixes GenFv by making it aware that AARCH64 can only be adjusted
(relocated) by multiples of 4 KB even if the PE/COFF metadata
indicates nothing of the sort.
I would rather change GenFv so it can place the PE/COFF image in such
a way that the .text section meets its minimum alignment without
necessarily aligning the start of the image to the same value, either
by omitting the PE/COFF header entirely in the FV (if that is allowed
by the spec) or by moving the header closer to the .text section and
loading the image SIZEOF_HEADERS bytes before the alignment boundary.
That way, the section alignment correctly reflects the 4 KB value
required to support the small C model for AArch64.
Well the TE image format kind of does this today. It replaces the PE/COFF headers with a smaller structure to save space, and contains information about where the PE/COFF header (image) would normally start, for the debugger.

Seems like you could add some code to pack the TE header down to the start of the .text section and get that space back.

Thanks,

Andrew Fish
Post by Ard Biesheuvel
--
Ard.
Olivier Martin
2015-07-10 16:13:33 UTC
Permalink
-----Original Message-----
Sent: 08 July 2015 18:50
To: Olivier Martin
Subject: Re: [PATCH] BaseTools/GenFw: Added AArch64 page-relative
relocations
When EDK2 is built for the small memory model with AArch64 LLVM, some
page-relative relocations (R_AARCH64_ADR_PREL_PG_HI21 and its
R_AARCH64_LDST(16|32|64|128)_ABS_LO12_NC companions) that were
not
supported before by EDK2 BaseTools are now needed.
This change adds support for these relocations in BaseTools.
Contributed-under: TianoCore Contribution Agreement 1.0
I think all the relocation arithmetic looks fine.
I do have a concern about the consequences of using the small C model in
this way: nothing in the metadata of the resulting PE/COFF images reflects
that the 4 KB alignment needs to be preserved in order to successfully
execute them, so you are essentially producing corrupt images. Every
PE/COFF loader needs to be modified (including the ones in GRUB and shim,
for instance) to prevent such images from being loaded in an incorrect way. (I
know that most PE/COFF loaders use
AllocatePages() which aligns these binaries at 4 KB implicitly, but this is not
mandatory)
So the correct way to do this would be to only use the small C model when
this alignment can be guaranteed, i.e., .text and .data are both aligned at 4
KB. With the latest GenFw changes in place (which sets PE/COFF section
alignment to the largest ELF input section alignment it encounters), the small
C model works correctly since the PE/COFF loaders adhere to the PE/COFF
section alignment. As a bonus, the ELF and PE/COFF images will be laid out
identically in memory, so all the recalculation arithmetic becomes
unnecessary (although it probably makes sense to perform some checks
here)
If I add support in 'MdePkg/Library/BasePeCoffLib' to prevent the image loading if the .text sections are not aligned on 4K when these page-relative relocations are used, would you consider this patchset?
In practical this error should never be exposed as AllocatePages() allocate the buffer on a 4K boundary.
The downside, of course, is that 4 KB alignment for both .text and .data
wastes a lot of space: 3.5 KB only for the padding between the PE/COFF
header and the start of .text, and 2 KB on average between .text and .data.
Due to the compression of non-XIP binaries, this is not such a penalty, but for
XIP it is prohibitive (even if these typically don't have a .data section)
I am going to have a look at GenFv to figure out if there is some way to work
around this, i.e., drop the PE/COFF headers or move them in some way.
In the mean time, I think this patch is good except the first hunk.
The small model relocation arithmetic can be merged separately, I think, and
the logic and policies around how and when to relocate PE/COFF images can
be addressed in a followup patch.
Sorry, I am not sure to understand which part of the patch you would like me to split...
--
Ard.
---
BaseTools/Source/C/Common/BasePeCoff.c | 14 +++
BaseTools/Source/C/Common/PeCoffLib.h | 13 +++
BaseTools/Source/C/Common/PeCoffLoaderEx.c | 58 +++++++++++
BaseTools/Source/C/GenFw/Elf64Convert.c | 159
+++++++++++++++++++++++------
BaseTools/Source/C/GenFw/elf_common.h | 4 +
5 files changed, 215 insertions(+), 33 deletions(-)
diff --git a/BaseTools/Source/C/Common/BasePeCoff.c
b/BaseTools/Source/C/Common/BasePeCoff.c
index afb45df..e1401f2 100644
--- a/BaseTools/Source/C/Common/BasePeCoff.c
+++ b/BaseTools/Source/C/Common/BasePeCoff.c
RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase
+ (UINTN) RelocDir->Size - 1);
}
+ // In order for page relative code relocations to work on AArch64 we
need to
+ // ensure that any address adjustment to images are 4k page aligned.
The page
+ // relative relocations are processed at build time as we do not have
enough
+ // information at runtime to recalculate them.
+ // The PE/COFF Base relocation types do not have a matching type to
describe
+ // page relative relocations so we do not know if they may be present in
the
+ // images. We must assume they are present and ensure the image is
properly
+ // aligned to keep these relocations valid.
+ if (ImageContext->Machine == EFI_IMAGE_MACHINE_AARCH64) {
+ if ((Adjust & 0xfff) != 0x0) {
+ return RETURN_LOAD_ERROR;
+ }
+ }
+
//
// Run the relocation information and apply the fixups
//
diff --git a/BaseTools/Source/C/Common/PeCoffLib.h
b/BaseTools/Source/C/Common/PeCoffLib.h
index b56dd75..2f8feb7 100644
--- a/BaseTools/Source/C/Common/PeCoffLib.h
+++ b/BaseTools/Source/C/Common/PeCoffLib.h
@@ -205,6 +205,19 @@ ThumbMovwMovtImmediatePatch (
IN UINT32 Address
);
+/**
+ Update AArch64 instruction immediate address data.
+
+
+**/
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Val
+ );
#endif
diff --git a/BaseTools/Source/C/Common/PeCoffLoaderEx.c
b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
index b7b7227..3864391 100644
--- a/BaseTools/Source/C/Common/PeCoffLoaderEx.c
+++ b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
@@ -466,6 +466,64 @@ PeCoffLoaderRelocateArmImage (
return RETURN_SUCCESS;
}
+
+/**
+ Update AArch64 instruction immediate address data.
+
+ to preserve sign extension where needed. Some
+ instructions can have positive and negative values.
+
+**/
+// The values below are used to match instructions based on the
architecture encoding
+// Don't support shifted imm12 for ADD instructions. Set as 0 in MASK and
INST
+#define AARCH64_ADD_MASK 0x1FC00000
+#define AARCH64_ADD_INST 0x11000000
+#define AARCH64_ADD_IMM 0x003FFC00
+#define IS_AARCH64_ADD(x) ((x & AARCH64_ADD_MASK) ==
AARCH64_ADD_INST)
+#define AARCH64_ADRP_MASK 0x9f000000
+#define AARCH64_ADRP_INST 0x90000000
+#define AARCH64_ADRP_IMM 0x60FFFFE0
+#define IS_AARCH64_ADRP(x) ((x & AARCH64_ADRP_MASK) ==
AARCH64_ADRP_INST)
+#define AARCH64_LDST_MASK 0x3b000000
+#define AARCH64_LDST_INST 0x39000000
+#define AARCH64_LDST_IMM 0x003FFC00
+#define IS_AARCH64_LDST(x) ((x & AARCH64_LDST_MASK) ==
AARCH64_LDST_INST)
+
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Value
+ )
+{
+ UINT32 Patch;
+ RETURN_STATUS Status;
+
+ Status = RETURN_UNSUPPORTED;
+
+ // Disassemble and update the instruction
+ if (IS_AARCH64_ADD (*Instruction)) {
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_ADD_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_ADRP (*Instruction)) {
+ Patch = ((Value & 0x3) << 29) | (((Value & 0x1FFFFC) >> 2) << 5);
+ *Instruction = (*Instruction & ~AARCH64_ADRP_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_LDST (*Instruction)) {
+ // Relocation types LDST8,16,32,64,128 specify different bitsizes.
+ // The Calling function knows the relocation type and has already
masked and
+ // scaled the address as needed.
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_LDST_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ }
+
+ return Status;
+}
+
RETURN_STATUS
PeCoffLoaderRelocateAArch64Image (
IN UINT16 *Reloc,
diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c
b/BaseTools/Source/C/GenFw/Elf64Convert.c
index d2becf1..355398f 100644
--- a/BaseTools/Source/C/GenFw/Elf64Convert.c
+++ b/BaseTools/Source/C/GenFw/Elf64Convert.c
@@ -709,56 +709,148 @@ WriteSections64 (
Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64
relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
}
} else if (mEhdr->e_machine == EM_AARCH64) {
-
- // AARCH64 GCC uses RELA relocation, so all relocations have to be
fixed up.
- // As opposed to ARM32 using REL.
-
+ // For ease of use specify relocations in terms of P, S and A as
+ // described the AArch64 ELF specification
+ UINT64 P, S;
+ INT64 A;
+ RETURN_STATUS Status;
+
+ // P - Address of the 'Place' being relocated
+ // S - Address of the Symbol
+ // A - The Addend for the relocation
+ P = (UINT64)(SecOffset + (Rel->r_offset - SecShdr->sh_addr));
+ S = (UINT64)(Sym->st_value - SymShdr->sh_addr +
mCoffSectionsOffset[Sym->st_shndx]);
+ A = (INT64)(Rel->r_addend);
+
+ // Some versions of the AArch64 GCC linker does not update the ELF
+ // relocations properly when doing the final static link. For this
+ // reason we do not fully recalculate the relocations that it might
+ // use with the Large memory model. We rely on the assumption
that the
+ // code sections affected by these relocations are not reordered
going
+ // from ELF to PE/COFF and a simple offset adjustment is sufficient.
+ // In the case of the ARM LLVM based compiler the relocation
+ // information is correct and as such we can use the small memory
+ // model and recalculate the relocations based on 'Place', 'Symbol'
+ // and 'Addend' information. At some point in the future this should
+ // be be done for AArch64 GCC as well.
switch (ELF_R_TYPE(Rel->r_info)) {
+ // Ideally we should recalculate all relocations in case the code
+ // sections moved around, but in some AArch64 GCC versions this is
+ // currently not working correctly.
+
+ // Relative relocations
- if (Rel->r_addend != 0 ) { /* TODO */
R_AARCH64_ADR_PREL_LO21 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_ADR_PREL_LO21: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
- if (Rel->r_addend != 0 ) { /* TODO */
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_CONDBR19
Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CONDBR19: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
- if (Rel->r_addend != 0 ) { /* TODO */
R_AARCH64_LD_PREL_LO19 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_LD_PREL_LO19: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CALL26: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ break;
+
- if (Rel->r_addend != 0 ) {
- // Some references to static functions sometime start at the base
of .text + addend.
- // It is safe to ignore these relocations because they patch a `BL`
instructions that
- // contains an offset from the instruction itself and there is only a
single .text section.
- // So we check if the symbol is a "section symbol"
- if (ELF64_ST_TYPE (Sym->st_info) == STT_SECTION) {
- break;
- }
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26
Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_JUMP26: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported
ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.",
mInImageName);
+ // We need to fully recalculate this relocation. This is used with the
small memory model.
+ // Reloc = PAGE(S+A) - PAGE(P) ; Page = 4k
+ VerboseMsg ("R_AARCH64_ADR_PREL_PG_HI21: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ INT32 Tmp = R_AARCH64_PAGE (S + A) - R_AARCH64_PAGE (P);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, Tmp / 4096);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
break;
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported
ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.",
mInImageName);
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ADD_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) &
R_AARCH64_PAGE_MASK);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST8_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) &
R_AARCH64_PAGE_MASK);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST16_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 1 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST32_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 2 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST64_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 3 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST128_ABS_LO12_NC: Targ =
0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 4 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
break;
// Absolute relocations.
+ // GCC with Large memory model uses this one. Don't recalculate
the
+ // relocation, just do the section offset adjustment. This assumes
+ // the relevant sections are not getting reordered.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ABS64: Targ = 0x%08lx,
*Targ=0x%08lx\n", (UINT64)Targ, *(UINT64 *)Targ);
+
+ // *Targ = *Targ - elf-section-addr[bss] + coff-section-addr[bss]
*(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr +
mCoffSectionsOffset[Sym->st_shndx];
break;
@@ -838,17 +930,18 @@ WriteRelocations64 (
break;
+ // These relocations are used together
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s
unsupported ELF EM_AARCH64 relocation
R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);
- break;
-
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s
unsupported ELF EM_AARCH64 relocation
R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);
break;
+ // Write DIR64 to the PE/COFF reloc fixup list
CoffAddFixup(
(UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]
+ (Rel->r_offset - SecShdr->sh_addr)),
diff --git a/BaseTools/Source/C/GenFw/elf_common.h
b/BaseTools/Source/C/GenFw/elf_common.h
index 766d0e4..d9057b6 100644
--- a/BaseTools/Source/C/GenFw/elf_common.h
+++ b/BaseTools/Source/C/GenFw/elf_common.h
@@ -673,6 +673,10 @@ typedef struct {
#define R_AARCH64_TLS_DTPREL32 1031 /* DTPREL(S+A) */
#define R_AARCH64_TLS_DTPMOD32 1032 /* LDM(S) */
#define R_AARCH64_TLS_TPREL32 1033 /* DTPREL(S+A) */
+/* AArch64 page relative relocations use 4k pages. */
+#define R_AARCH64_PAGE_SIZE 0x1000
+#define R_AARCH64_PAGE_MASK 0xfffUL
+#define R_AARCH64_PAGE(x) ((x) &
~R_AARCH64_PAGE_MASK)
#define R_ALPHA_NONE 0 /* No reloc */
#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
--
2.1.1
-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2557590
ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2548782
Ard Biesheuvel
2015-07-10 16:26:41 UTC
Permalink
Post by Olivier Martin
-----Original Message-----
Sent: 08 July 2015 18:50
To: Olivier Martin
Subject: Re: [PATCH] BaseTools/GenFw: Added AArch64 page-relative
relocations
When EDK2 is built for the small memory model with AArch64 LLVM, some
page-relative relocations (R_AARCH64_ADR_PREL_PG_HI21 and its
R_AARCH64_LDST(16|32|64|128)_ABS_LO12_NC companions) that were
not
supported before by EDK2 BaseTools are now needed.
This change adds support for these relocations in BaseTools.
Contributed-under: TianoCore Contribution Agreement 1.0
I think all the relocation arithmetic looks fine.
I do have a concern about the consequences of using the small C model in
this way: nothing in the metadata of the resulting PE/COFF images reflects
that the 4 KB alignment needs to be preserved in order to successfully
execute them, so you are essentially producing corrupt images. Every
PE/COFF loader needs to be modified (including the ones in GRUB and shim,
for instance) to prevent such images from being loaded in an incorrect way. (I
know that most PE/COFF loaders use
AllocatePages() which aligns these binaries at 4 KB implicitly, but this is not
mandatory)
So the correct way to do this would be to only use the small C model when
this alignment can be guaranteed, i.e., .text and .data are both aligned at 4
KB. With the latest GenFw changes in place (which sets PE/COFF section
alignment to the largest ELF input section alignment it encounters), the small
C model works correctly since the PE/COFF loaders adhere to the PE/COFF
section alignment. As a bonus, the ELF and PE/COFF images will be laid out
identically in memory, so all the recalculation arithmetic becomes
unnecessary (although it probably makes sense to perform some checks
here)
If I add support in 'MdePkg/Library/BasePeCoffLib' to prevent the image loading if the .text sections are not aligned on 4K when these page-relative relocations are used, would you consider this patchset?
In practical this error should never be exposed as AllocatePages() allocate the buffer on a 4K boundary.
The downside, of course, is that 4 KB alignment for both .text and .data
wastes a lot of space: 3.5 KB only for the padding between the PE/COFF
header and the start of .text, and 2 KB on average between .text and .data.
Due to the compression of non-XIP binaries, this is not such a penalty, but for
XIP it is prohibitive (even if these typically don't have a .data section)
I am going to have a look at GenFv to figure out if there is some way to work
around this, i.e., drop the PE/COFF headers or move them in some way.
In the mean time, I think this patch is good except the first hunk.
The small model relocation arithmetic can be merged separately, I think, and
the logic and policies around how and when to relocate PE/COFF images can
be addressed in a followup patch.
Sorry, I am not sure to understand which part of the patch you would like me to split...
My general point is that such relocations should only be allowed if
the section alignment is at least 4 KB. This results in bigger files
generally, so I have already implemented support in GenFw for smaller
file alignment if the section alignment is >= 4 KB (this is allowed by
the PE/COFF spec) Next step is to massage GenFv to allow such images
if it manages to place it such that the section alignment is met for
all sections it contains. I think this may be doable but I haven't
managed yet. It would also require a separate LD overlay script to put
all input section into .text (since XIP modules shouldn't have
writable data anyway). This should greatly reduce the bloat in TE
images with 4 KB section alignment.

I quite dislike the idea of creating binaries that happen to work
simply because we know they should be loaded at a certain alignment
that is not communicated via its metadata.

So my position is that the first hunk should be dropped, and instead,
the patch should ensure that these relocations are only encountered in
binaries that have sufficient section alignment, and error out
otherwise. For now, that will result in bigger XIP binaries when
building with LLVM, and hopefully we can fix that later. I am quite
eager to enable the small C model on GCC as well, which obviously
suffers from the same problems.
--
Ard.
Post by Olivier Martin
---
BaseTools/Source/C/Common/BasePeCoff.c | 14 +++
BaseTools/Source/C/Common/PeCoffLib.h | 13 +++
BaseTools/Source/C/Common/PeCoffLoaderEx.c | 58 +++++++++++
BaseTools/Source/C/GenFw/Elf64Convert.c | 159
+++++++++++++++++++++++------
BaseTools/Source/C/GenFw/elf_common.h | 4 +
5 files changed, 215 insertions(+), 33 deletions(-)
diff --git a/BaseTools/Source/C/Common/BasePeCoff.c
b/BaseTools/Source/C/Common/BasePeCoff.c
index afb45df..e1401f2 100644
--- a/BaseTools/Source/C/Common/BasePeCoff.c
+++ b/BaseTools/Source/C/Common/BasePeCoff.c
RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase
+ (UINTN) RelocDir->Size - 1);
}
+ // In order for page relative code relocations to work on AArch64 we
need to
+ // ensure that any address adjustment to images are 4k page aligned.
The page
+ // relative relocations are processed at build time as we do not have
enough
+ // information at runtime to recalculate them.
+ // The PE/COFF Base relocation types do not have a matching type to
describe
+ // page relative relocations so we do not know if they may be present in
the
+ // images. We must assume they are present and ensure the image is
properly
+ // aligned to keep these relocations valid.
+ if (ImageContext->Machine == EFI_IMAGE_MACHINE_AARCH64) {
+ if ((Adjust & 0xfff) != 0x0) {
+ return RETURN_LOAD_ERROR;
+ }
+ }
+
//
// Run the relocation information and apply the fixups
//
diff --git a/BaseTools/Source/C/Common/PeCoffLib.h
b/BaseTools/Source/C/Common/PeCoffLib.h
index b56dd75..2f8feb7 100644
--- a/BaseTools/Source/C/Common/PeCoffLib.h
+++ b/BaseTools/Source/C/Common/PeCoffLib.h
@@ -205,6 +205,19 @@ ThumbMovwMovtImmediatePatch (
IN UINT32 Address
);
+/**
+ Update AArch64 instruction immediate address data.
+
+
+**/
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Val
+ );
#endif
diff --git a/BaseTools/Source/C/Common/PeCoffLoaderEx.c
b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
index b7b7227..3864391 100644
--- a/BaseTools/Source/C/Common/PeCoffLoaderEx.c
+++ b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
@@ -466,6 +466,64 @@ PeCoffLoaderRelocateArmImage (
return RETURN_SUCCESS;
}
+
+/**
+ Update AArch64 instruction immediate address data.
+
+ to preserve sign extension where needed. Some
+ instructions can have positive and negative values.
+
+**/
+// The values below are used to match instructions based on the
architecture encoding
+// Don't support shifted imm12 for ADD instructions. Set as 0 in MASK and
INST
+#define AARCH64_ADD_MASK 0x1FC00000
+#define AARCH64_ADD_INST 0x11000000
+#define AARCH64_ADD_IMM 0x003FFC00
+#define IS_AARCH64_ADD(x) ((x & AARCH64_ADD_MASK) ==
AARCH64_ADD_INST)
+#define AARCH64_ADRP_MASK 0x9f000000
+#define AARCH64_ADRP_INST 0x90000000
+#define AARCH64_ADRP_IMM 0x60FFFFE0
+#define IS_AARCH64_ADRP(x) ((x & AARCH64_ADRP_MASK) ==
AARCH64_ADRP_INST)
+#define AARCH64_LDST_MASK 0x3b000000
+#define AARCH64_LDST_INST 0x39000000
+#define AARCH64_LDST_IMM 0x003FFC00
+#define IS_AARCH64_LDST(x) ((x & AARCH64_LDST_MASK) ==
AARCH64_LDST_INST)
+
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Value
+ )
+{
+ UINT32 Patch;
+ RETURN_STATUS Status;
+
+ Status = RETURN_UNSUPPORTED;
+
+ // Disassemble and update the instruction
+ if (IS_AARCH64_ADD (*Instruction)) {
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_ADD_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_ADRP (*Instruction)) {
+ Patch = ((Value & 0x3) << 29) | (((Value & 0x1FFFFC) >> 2) << 5);
+ *Instruction = (*Instruction & ~AARCH64_ADRP_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_LDST (*Instruction)) {
+ // Relocation types LDST8,16,32,64,128 specify different bitsizes.
+ // The Calling function knows the relocation type and has already
masked and
+ // scaled the address as needed.
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_LDST_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ }
+
+ return Status;
+}
+
RETURN_STATUS
PeCoffLoaderRelocateAArch64Image (
IN UINT16 *Reloc,
diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c
b/BaseTools/Source/C/GenFw/Elf64Convert.c
index d2becf1..355398f 100644
--- a/BaseTools/Source/C/GenFw/Elf64Convert.c
+++ b/BaseTools/Source/C/GenFw/Elf64Convert.c
@@ -709,56 +709,148 @@ WriteSections64 (
Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64
relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
}
} else if (mEhdr->e_machine == EM_AARCH64) {
-
- // AARCH64 GCC uses RELA relocation, so all relocations have to be
fixed up.
- // As opposed to ARM32 using REL.
-
+ // For ease of use specify relocations in terms of P, S and A as
+ // described the AArch64 ELF specification
+ UINT64 P, S;
+ INT64 A;
+ RETURN_STATUS Status;
+
+ // P - Address of the 'Place' being relocated
+ // S - Address of the Symbol
+ // A - The Addend for the relocation
+ P = (UINT64)(SecOffset + (Rel->r_offset - SecShdr->sh_addr));
+ S = (UINT64)(Sym->st_value - SymShdr->sh_addr +
mCoffSectionsOffset[Sym->st_shndx]);
+ A = (INT64)(Rel->r_addend);
+
+ // Some versions of the AArch64 GCC linker does not update the ELF
+ // relocations properly when doing the final static link. For this
+ // reason we do not fully recalculate the relocations that it might
+ // use with the Large memory model. We rely on the assumption
that the
+ // code sections affected by these relocations are not reordered
going
+ // from ELF to PE/COFF and a simple offset adjustment is sufficient.
+ // In the case of the ARM LLVM based compiler the relocation
+ // information is correct and as such we can use the small memory
+ // model and recalculate the relocations based on 'Place', 'Symbol'
+ // and 'Addend' information. At some point in the future this should
+ // be be done for AArch64 GCC as well.
switch (ELF_R_TYPE(Rel->r_info)) {
+ // Ideally we should recalculate all relocations in case the code
+ // sections moved around, but in some AArch64 GCC versions this is
+ // currently not working correctly.
+
+ // Relative relocations
- if (Rel->r_addend != 0 ) { /* TODO */
R_AARCH64_ADR_PREL_LO21 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_ADR_PREL_LO21: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
- if (Rel->r_addend != 0 ) { /* TODO */
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_CONDBR19
Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CONDBR19: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
- if (Rel->r_addend != 0 ) { /* TODO */
R_AARCH64_LD_PREL_LO19 Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_LD_PREL_LO19: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CALL26: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ break;
+
- if (Rel->r_addend != 0 ) {
- // Some references to static functions sometime start at the base
of .text + addend.
- // It is safe to ignore these relocations because they patch a `BL`
instructions that
- // contains an offset from the instruction itself and there is only a
single .text section.
- // So we check if the symbol is a "section symbol"
- if (ELF64_ST_TYPE (Sym->st_info) == STT_SECTION) {
- break;
- }
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26
Need to fixup with addend!.");
- }
+ // GCC with Large memory model uses this one. Leave as is for now.
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_JUMP26: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
break;
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported
ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.",
mInImageName);
+ // We need to fully recalculate this relocation. This is used with the
small memory model.
+ // Reloc = PAGE(S+A) - PAGE(P) ; Page = 4k
+ VerboseMsg ("R_AARCH64_ADR_PREL_PG_HI21: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ INT32 Tmp = R_AARCH64_PAGE (S + A) - R_AARCH64_PAGE (P);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, Tmp / 4096);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
break;
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported
ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.",
mInImageName);
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ADD_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) &
R_AARCH64_PAGE_MASK);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST8_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) &
R_AARCH64_PAGE_MASK);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST16_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 1 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST32_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 2 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST64_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 3 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with the
small memory model.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST128_ABS_LO12_NC: Targ =
0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 4 );
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching ELF
EM_AARCH64 relocation failed.", mInImageName);
+ }
break;
// Absolute relocations.
+ // GCC with Large memory model uses this one. Don't recalculate
the
+ // relocation, just do the section offset adjustment. This assumes
+ // the relevant sections are not getting reordered.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ABS64: Targ = 0x%08lx,
*Targ=0x%08lx\n", (UINT64)Targ, *(UINT64 *)Targ);
+
+ // *Targ = *Targ - elf-section-addr[bss] + coff-section-addr[bss]
*(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr +
mCoffSectionsOffset[Sym->st_shndx];
break;
@@ -838,17 +930,18 @@ WriteRelocations64 (
break;
+ // These relocations are used together
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s
unsupported ELF EM_AARCH64 relocation
R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);
- break;
-
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s
unsupported ELF EM_AARCH64 relocation
R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);
break;
+ // Write DIR64 to the PE/COFF reloc fixup list
CoffAddFixup(
(UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]
+ (Rel->r_offset - SecShdr->sh_addr)),
diff --git a/BaseTools/Source/C/GenFw/elf_common.h
b/BaseTools/Source/C/GenFw/elf_common.h
index 766d0e4..d9057b6 100644
--- a/BaseTools/Source/C/GenFw/elf_common.h
+++ b/BaseTools/Source/C/GenFw/elf_common.h
@@ -673,6 +673,10 @@ typedef struct {
#define R_AARCH64_TLS_DTPREL32 1031 /* DTPREL(S+A) */
#define R_AARCH64_TLS_DTPMOD32 1032 /* LDM(S) */
#define R_AARCH64_TLS_TPREL32 1033 /* DTPREL(S+A) */
+/* AArch64 page relative relocations use 4k pages. */
+#define R_AARCH64_PAGE_SIZE 0x1000
+#define R_AARCH64_PAGE_MASK 0xfffUL
+#define R_AARCH64_PAGE(x) ((x) &
~R_AARCH64_PAGE_MASK)
#define R_ALPHA_NONE 0 /* No reloc */
#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
--
2.1.1
-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2557590
ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2548782
Olivier Martin
2015-07-13 14:54:43 UTC
Permalink
Sorry, I am bit slow today... Sorry again to ask clarification but what do you mean by: " So my position is that the first hunk should be dropped, and instead, the patch should ensure that these relocations are only encountered in binaries that have sufficient section alignment, and error out otherwise."

Would you like me to remove this condition " if (ImageContext->Machine == EFI_IMAGE_MACHINE_AARCH64) {...}"
And move this condition into each relocations that need to be page relative?


When you say " because we know they should be loaded at a certain alignment that is not communicated via its metadata". I had the impression and AndrewF also confirmed my impression is the alignment is part of the PE/COFF headers. Have a look at PE_COFF_LOADER_IMAGE_CONTEXT.SectionAlignment in BaseTools/Source/C/Common/PeCoffLib.h and https://msdn.microsoft.com/en-gb/library/ms809762.aspx.
-----Original Message-----
Sent: 10 July 2015 17:27
To: Olivier Martin
Subject: Re: [PATCH] BaseTools/GenFw: Added AArch64 page-relative
relocations
Post by Olivier Martin
-----Original Message-----
Sent: 08 July 2015 18:50
To: Olivier Martin
Subject: Re: [PATCH] BaseTools/GenFw: Added AArch64 page-relative
relocations
Post by Olivier Martin
When EDK2 is built for the small memory model with AArch64 LLVM,
some page-relative relocations (R_AARCH64_ADR_PREL_PG_HI21 and
its
Post by Olivier Martin
Post by Olivier Martin
R_AARCH64_LDST(16|32|64|128)_ABS_LO12_NC companions) that
were
Post by Olivier Martin
not
Post by Olivier Martin
supported before by EDK2 BaseTools are now needed.
This change adds support for these relocations in BaseTools.
Contributed-under: TianoCore Contribution Agreement 1.0
I think all the relocation arithmetic looks fine.
I do have a concern about the consequences of using the small C model
in this way: nothing in the metadata of the resulting PE/COFF images
reflects that the 4 KB alignment needs to be preserved in order to
successfully execute them, so you are essentially producing corrupt
images. Every PE/COFF loader needs to be modified (including the ones
in GRUB and shim, for instance) to prevent such images from being
loaded in an incorrect way. (I know that most PE/COFF loaders use
AllocatePages() which aligns these binaries at 4 KB implicitly, but this is not
mandatory)
So the correct way to do this would be to only use the small C model
when this alignment can be guaranteed, i.e., .text and .data are both
aligned at 4 KB. With the latest GenFw changes in place (which sets
PE/COFF section alignment to the largest ELF input section alignment
it encounters), the small C model works correctly since the PE/COFF
loaders adhere to the PE/COFF section alignment. As a bonus, the ELF
and PE/COFF images will be laid out identically in memory, so all the
recalculation arithmetic becomes unnecessary (although it probably
makes sense to perform some checks
here)
If I add support in 'MdePkg/Library/BasePeCoffLib' to prevent the image
loading if the .text sections are not aligned on 4K when these page-relative
relocations are used, would you consider this patchset?
Post by Olivier Martin
In practical this error should never be exposed as AllocatePages() allocate
the buffer on a 4K boundary.
Post by Olivier Martin
The downside, of course, is that 4 KB alignment for both .text and
.data wastes a lot of space: 3.5 KB only for the padding between the
PE/COFF header and the start of .text, and 2 KB on average between .text
and .data.
Post by Olivier Martin
Due to the compression of non-XIP binaries, this is not such a
penalty, but for XIP it is prohibitive (even if these typically don't
have a .data section)
I am going to have a look at GenFv to figure out if there is some way
to work around this, i.e., drop the PE/COFF headers or move them in
some way.
Post by Olivier Martin
In the mean time, I think this patch is good except the first hunk.
The small model relocation arithmetic can be merged separately, I
think, and the logic and policies around how and when to relocate
PE/COFF images can be addressed in a followup patch.
Sorry, I am not sure to understand which part of the patch you would like
me to split...
My general point is that such relocations should only be allowed if the section
alignment is at least 4 KB. This results in bigger files generally, so I have
already implemented support in GenFw for smaller file alignment if the
section alignment is >= 4 KB (this is allowed by the PE/COFF spec) Next step is
to massage GenFv to allow such images if it manages to place it such that the
section alignment is met for all sections it contains. I think this may be doable
but I haven't managed yet. It would also require a separate LD overlay script
to put all input section into .text (since XIP modules shouldn't have writable
data anyway). This should greatly reduce the bloat in TE images with 4 KB
section alignment.
I quite dislike the idea of creating binaries that happen to work simply
because we know they should be loaded at a certain alignment that is not
communicated via its metadata.
So my position is that the first hunk should be dropped, and instead, the
patch should ensure that these relocations are only encountered in binaries
that have sufficient section alignment, and error out otherwise. For now,
that will result in bigger XIP binaries when building with LLVM, and hopefully
we can fix that later. I am quite eager to enable the small C model on GCC as
well, which obviously suffers from the same problems.
--
Ard.
Post by Olivier Martin
Post by Olivier Martin
---
BaseTools/Source/C/Common/BasePeCoff.c | 14 +++
BaseTools/Source/C/Common/PeCoffLib.h | 13 +++
BaseTools/Source/C/Common/PeCoffLoaderEx.c | 58 +++++++++++
BaseTools/Source/C/GenFw/Elf64Convert.c | 159
+++++++++++++++++++++++------
Post by Olivier Martin
BaseTools/Source/C/GenFw/elf_common.h | 4 +
5 files changed, 215 insertions(+), 33 deletions(-)
diff --git a/BaseTools/Source/C/Common/BasePeCoff.c
b/BaseTools/Source/C/Common/BasePeCoff.c
Post by Olivier Martin
index afb45df..e1401f2 100644
--- a/BaseTools/Source/C/Common/BasePeCoff.c
+++ b/BaseTools/Source/C/Common/BasePeCoff.c
RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN)
RelocBase
Post by Olivier Martin
+ (UINTN) RelocDir->Size - 1);
Post by Olivier Martin
}
+ // In order for page relative code relocations to work on AArch64 we
need to
Post by Olivier Martin
+ // ensure that any address adjustment to images are 4k page aligned.
The page
Post by Olivier Martin
+ // relative relocations are processed at build time as we do not have
enough
Post by Olivier Martin
+ // information at runtime to recalculate them.
+ // The PE/COFF Base relocation types do not have a matching type to
describe
Post by Olivier Martin
+ // page relative relocations so we do not know if they may be present
in
Post by Olivier Martin
the
Post by Olivier Martin
+ // images. We must assume they are present and ensure the image is
properly
Post by Olivier Martin
+ // aligned to keep these relocations valid.
+ if (ImageContext->Machine == EFI_IMAGE_MACHINE_AARCH64) {
+ if ((Adjust & 0xfff) != 0x0) {
+ return RETURN_LOAD_ERROR;
+ }
+ }
+
//
// Run the relocation information and apply the fixups
//
diff --git a/BaseTools/Source/C/Common/PeCoffLib.h
b/BaseTools/Source/C/Common/PeCoffLib.h
Post by Olivier Martin
index b56dd75..2f8feb7 100644
--- a/BaseTools/Source/C/Common/PeCoffLib.h
+++ b/BaseTools/Source/C/Common/PeCoffLib.h
@@ -205,6 +205,19 @@ ThumbMovwMovtImmediatePatch (
IN UINT32 Address
);
+/**
+ Update AArch64 instruction immediate address data.
+
+
+**/
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Val
+ );
#endif
diff --git a/BaseTools/Source/C/Common/PeCoffLoaderEx.c
b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
Post by Olivier Martin
index b7b7227..3864391 100644
--- a/BaseTools/Source/C/Common/PeCoffLoaderEx.c
+++ b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
@@ -466,6 +466,64 @@ PeCoffLoaderRelocateArmImage (
return RETURN_SUCCESS;
}
+
+/**
+ Update AArch64 instruction immediate address data.
+
value
Post by Olivier Martin
Post by Olivier Martin
+ to preserve sign extension where needed. Some
+ instructions can have positive and negative values.
+
+**/
+// The values below are used to match instructions based on the
architecture encoding
Post by Olivier Martin
+// Don't support shifted imm12 for ADD instructions. Set as 0 in MASK
and
Post by Olivier Martin
INST
Post by Olivier Martin
+#define AARCH64_ADD_MASK 0x1FC00000
+#define AARCH64_ADD_INST 0x11000000
+#define AARCH64_ADD_IMM 0x003FFC00
+#define IS_AARCH64_ADD(x) ((x & AARCH64_ADD_MASK) ==
AARCH64_ADD_INST)
Post by Olivier Martin
+#define AARCH64_ADRP_MASK 0x9f000000
+#define AARCH64_ADRP_INST 0x90000000
+#define AARCH64_ADRP_IMM 0x60FFFFE0
+#define IS_AARCH64_ADRP(x) ((x & AARCH64_ADRP_MASK) ==
AARCH64_ADRP_INST)
Post by Olivier Martin
+#define AARCH64_LDST_MASK 0x3b000000
+#define AARCH64_LDST_INST 0x39000000
+#define AARCH64_LDST_IMM 0x003FFC00
+#define IS_AARCH64_LDST(x) ((x & AARCH64_LDST_MASK) ==
AARCH64_LDST_INST)
Post by Olivier Martin
+
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Value
+ )
+{
+ UINT32 Patch;
+ RETURN_STATUS Status;
+
+ Status = RETURN_UNSUPPORTED;
+
+ // Disassemble and update the instruction
+ if (IS_AARCH64_ADD (*Instruction)) {
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_ADD_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_ADRP (*Instruction)) {
+ Patch = ((Value & 0x3) << 29) | (((Value & 0x1FFFFC) >> 2) << 5);
+ *Instruction = (*Instruction & ~AARCH64_ADRP_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_LDST (*Instruction)) {
+ // Relocation types LDST8,16,32,64,128 specify different bitsizes.
+ // The Calling function knows the relocation type and has already
masked and
Post by Olivier Martin
+ // scaled the address as needed.
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_LDST_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ }
+
+ return Status;
+}
+
RETURN_STATUS
PeCoffLoaderRelocateAArch64Image (
IN UINT16 *Reloc,
diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c
b/BaseTools/Source/C/GenFw/Elf64Convert.c
Post by Olivier Martin
index d2becf1..355398f 100644
--- a/BaseTools/Source/C/GenFw/Elf64Convert.c
+++ b/BaseTools/Source/C/GenFw/Elf64Convert.c
@@ -709,56 +709,148 @@ WriteSections64 (
Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64
relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
Post by Olivier Martin
}
} else if (mEhdr->e_machine == EM_AARCH64) {
-
- // AARCH64 GCC uses RELA relocation, so all relocations have to be
fixed up.
Post by Olivier Martin
- // As opposed to ARM32 using REL.
-
+ // For ease of use specify relocations in terms of P, S and A as
+ // described the AArch64 ELF specification
+ UINT64 P, S;
+ INT64 A;
+ RETURN_STATUS Status;
+
+ // P - Address of the 'Place' being relocated
+ // S - Address of the Symbol
+ // A - The Addend for the relocation
+ P = (UINT64)(SecOffset + (Rel->r_offset - SecShdr->sh_addr));
+ S = (UINT64)(Sym->st_value - SymShdr->sh_addr +
mCoffSectionsOffset[Sym->st_shndx]);
Post by Olivier Martin
+ A = (INT64)(Rel->r_addend);
+
+ // Some versions of the AArch64 GCC linker does not update the
ELF
Post by Olivier Martin
Post by Olivier Martin
+ // relocations properly when doing the final static link. For this
+ // reason we do not fully recalculate the relocations that it might
+ // use with the Large memory model. We rely on the assumption
that the
Post by Olivier Martin
+ // code sections affected by these relocations are not reordered
going
Post by Olivier Martin
+ // from ELF to PE/COFF and a simple offset adjustment is
sufficient.
Post by Olivier Martin
Post by Olivier Martin
+ // In the case of the ARM LLVM based compiler the relocation
+ // information is correct and as such we can use the small memory
+ // model and recalculate the relocations based on 'Place', 'Symbol'
+ // and 'Addend' information. At some point in the future this
should
Post by Olivier Martin
Post by Olivier Martin
+ // be be done for AArch64 GCC as well.
switch (ELF_R_TYPE(Rel->r_info)) {
+ // Ideally we should recalculate all relocations in case the code
+ // sections moved around, but in some AArch64 GCC versions this
is
Post by Olivier Martin
Post by Olivier Martin
+ // currently not working correctly.
+
+ // Relative relocations
- if (Rel->r_addend != 0 ) { /* TODO */
R_AARCH64_ADR_PREL_LO21 Need to fixup with addend!.");
Post by Olivier Martin
- }
+ // GCC with Large memory model uses this one. Leave as is for
now.
Post by Olivier Martin
Post by Olivier Martin
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_ADR_PREL_LO21: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
break;
- if (Rel->r_addend != 0 ) { /* TODO */
R_AARCH64_CONDBR19
Post by Olivier Martin
Need to fixup with addend!.");
Post by Olivier Martin
- }
+ // GCC with Large memory model uses this one. Leave as is for
now.
Post by Olivier Martin
Post by Olivier Martin
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CONDBR19: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
break;
- if (Rel->r_addend != 0 ) { /* TODO */
R_AARCH64_LD_PREL_LO19 Need to fixup with addend!.");
Post by Olivier Martin
- }
+ // GCC with Large memory model uses this one. Leave as is for
now.
Post by Olivier Martin
Post by Olivier Martin
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_LD_PREL_LO19: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
break;
+ // GCC with Large memory model uses this one. Leave as is for
now.
Post by Olivier Martin
Post by Olivier Martin
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CALL26: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ break;
+
- if (Rel->r_addend != 0 ) {
- // Some references to static functions sometime start at the
base
Post by Olivier Martin
of .text + addend.
Post by Olivier Martin
- // It is safe to ignore these relocations because they patch a `BL`
instructions that
Post by Olivier Martin
- // contains an offset from the instruction itself and there is only
a
Post by Olivier Martin
single .text section.
Post by Olivier Martin
- // So we check if the symbol is a "section symbol"
- if (ELF64_ST_TYPE (Sym->st_info) == STT_SECTION) {
- break;
- }
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26
Need to fixup with addend!.");
Post by Olivier Martin
- }
+ // GCC with Large memory model uses this one. Leave as is for
now.
Post by Olivier Martin
Post by Olivier Martin
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_JUMP26: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
break;
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s
unsupported
Post by Olivier Martin
ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.",
mInImageName);
Post by Olivier Martin
+ // We need to fully recalculate this relocation. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = PAGE(S+A) - PAGE(P) ; Page = 4k
+ VerboseMsg ("R_AARCH64_ADR_PREL_PG_HI21: Targ =
0x%08lx,
Post by Olivier Martin
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ INT32 Tmp = R_AARCH64_PAGE (S + A) - R_AARCH64_PAGE (P);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, Tmp / 4096);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
break;
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s
unsupported
Post by Olivier Martin
ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.",
mInImageName);
Post by Olivier Martin
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ADD_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) &
R_AARCH64_PAGE_MASK);
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST8_ABS_LO12_NC: Targ =
0x%08lx,
Post by Olivier Martin
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) &
R_AARCH64_PAGE_MASK);
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST16_ABS_LO12_NC: Targ =
0x%08lx,
Post by Olivier Martin
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 1 );
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST32_ABS_LO12_NC: Targ =
0x%08lx,
Post by Olivier Martin
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 2 );
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST64_ABS_LO12_NC: Targ =
0x%08lx,
Post by Olivier Martin
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 3 );
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST128_ABS_LO12_NC: Targ =
0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 4 );
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
break;
// Absolute relocations.
+ // GCC with Large memory model uses this one. Don't recalculate
the
Post by Olivier Martin
+ // relocation, just do the section offset adjustment. This
assumes
Post by Olivier Martin
Post by Olivier Martin
+ // the relevant sections are not getting reordered.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ABS64: Targ = 0x%08lx,
*Targ=0x%08lx\n", (UINT64)Targ, *(UINT64 *)Targ);
Post by Olivier Martin
+
+ // *Targ = *Targ - elf-section-addr[bss] + coff-section-addr[bss]
*(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr +
mCoffSectionsOffset[Sym->st_shndx];
Post by Olivier Martin
break;
@@ -838,17 +930,18 @@ WriteRelocations64 (
break;
+ // These relocations are used together
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s
unsupported ELF EM_AARCH64 relocation
R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);
Post by Olivier Martin
- break;
-
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s
unsupported ELF EM_AARCH64 relocation
R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);
Post by Olivier Martin
break;
+ // Write DIR64 to the PE/COFF reloc fixup list
CoffAddFixup(
(UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]
+ (Rel->r_offset - SecShdr->sh_addr)),
diff --git a/BaseTools/Source/C/GenFw/elf_common.h
b/BaseTools/Source/C/GenFw/elf_common.h
Post by Olivier Martin
index 766d0e4..d9057b6 100644
--- a/BaseTools/Source/C/GenFw/elf_common.h
+++ b/BaseTools/Source/C/GenFw/elf_common.h
@@ -673,6 +673,10 @@ typedef struct {
#define R_AARCH64_TLS_DTPREL32 1031 /* DTPREL(S+A)
*/
Post by Olivier Martin
Post by Olivier Martin
#define R_AARCH64_TLS_DTPMOD32 1032 /* LDM(S) */
#define R_AARCH64_TLS_TPREL32 1033 /* DTPREL(S+A)
*/
Post by Olivier Martin
Post by Olivier Martin
+/* AArch64 page relative relocations use 4k pages. */
+#define R_AARCH64_PAGE_SIZE 0x1000
+#define R_AARCH64_PAGE_MASK 0xfffUL
+#define R_AARCH64_PAGE(x) ((x) &
~R_AARCH64_PAGE_MASK)
Post by Olivier Martin
#define R_ALPHA_NONE 0 /* No reloc */
#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
--
2.1.1
-- IMPORTANT NOTICE: The contents of this email and any attachments are
confidential and may also be privileged. If you are not the intended recipient,
please notify the sender immediately and do not disclose the contents to any
other person, use it for any purpose, or store or copy the information in any
medium. Thank you.
Post by Olivier Martin
ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ,
Registered in England & Wales, Company No: 2557590
Post by Olivier Martin
ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1
9NJ, Registered in England & Wales, Company No: 2548782
-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2557590
ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2548782
Ard Biesheuvel
2015-07-13 15:04:19 UTC
Permalink
Post by Olivier Martin
Sorry, I am bit slow today... Sorry again to ask clarification but what do you mean by: " So my position is that the first hunk should be dropped, and instead, the patch should ensure that these relocations are only encountered in binaries that have sufficient section alignment, and error out otherwise."
Would you like me to remove this condition " if (ImageContext->Machine == EFI_IMAGE_MACHINE_AARCH64) {...}"
And move this condition into each relocations that need to be page relative?
Yes, see below.
Post by Olivier Martin
When you say " because we know they should be loaded at a certain alignment that is not communicated via its metadata". I had the impression and AndrewF also confirmed my impression is the alignment is part of the PE/COFF headers. Have a look at PE_COFF_LOADER_IMAGE_CONTEXT.SectionAlignment in BaseTools/Source/C/Common/PeCoffLib.h and https://msdn.microsoft.com/en-gb/library/ms809762.aspx.
Yes, but that alignment was fixed at 0x20 up until a couple of weeks
ago, and your (Harry's) code does not check whether its value is >= 4
KB.

So we need something like this [in WriteSections64():case
R_AARCH64_ADR_PREL_PG_HI21]:

"""
// ADRP/ADD and ADRP/LDR pairs require 4 KB section alignment
if (mCoffSectionAlignment < R_AARCH64_PAGE_SIZE) {
Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64
small model requires 4 KB section alignment.", mInImageName);
break;
}
"""

and the appropriate ALIGN(0x1000) declarations in the various linker scripts.

So with those changes, all small model PE/COFF binaries will have
section alignment set to at least 4 KB.

There is a big downside, though, and I am currently trying to figure
out if there is anything we can do about it: the XIP images will also
have 4 KB section alignment, which means 3.5 KB of wasted space
between the header and the first section, and 2 KB wasted space on
average between subsequent sections. I have a patch that allows file
alignment to be smaller than section alignment in case section
alignment < 4 KB (which is allowed by the PE/COFF spec), which is a
first step towards wasting less space in the XIP binaries. What I
haven't figured out yet is how to put such binaries into a FV image in
a way that they can be executed in place without forcing the header to
be section aligned. I think it is possible, but I am not quite there
yet.

I will try to post an RFC series later today or tomorrow to illustrate
what I am trying to do.
--
Ard.
Post by Olivier Martin
-----Original Message-----
Sent: 10 July 2015 17:27
To: Olivier Martin
Subject: Re: [PATCH] BaseTools/GenFw: Added AArch64 page-relative
relocations
Post by Olivier Martin
-----Original Message-----
Sent: 08 July 2015 18:50
To: Olivier Martin
Subject: Re: [PATCH] BaseTools/GenFw: Added AArch64 page-relative
relocations
Post by Olivier Martin
When EDK2 is built for the small memory model with AArch64 LLVM,
some page-relative relocations (R_AARCH64_ADR_PREL_PG_HI21 and
its
Post by Olivier Martin
Post by Olivier Martin
R_AARCH64_LDST(16|32|64|128)_ABS_LO12_NC companions) that
were
Post by Olivier Martin
not
Post by Olivier Martin
supported before by EDK2 BaseTools are now needed.
This change adds support for these relocations in BaseTools.
Contributed-under: TianoCore Contribution Agreement 1.0
I think all the relocation arithmetic looks fine.
I do have a concern about the consequences of using the small C model
in this way: nothing in the metadata of the resulting PE/COFF images
reflects that the 4 KB alignment needs to be preserved in order to
successfully execute them, so you are essentially producing corrupt
images. Every PE/COFF loader needs to be modified (including the ones
in GRUB and shim, for instance) to prevent such images from being
loaded in an incorrect way. (I know that most PE/COFF loaders use
AllocatePages() which aligns these binaries at 4 KB implicitly, but this is not
mandatory)
So the correct way to do this would be to only use the small C model
when this alignment can be guaranteed, i.e., .text and .data are both
aligned at 4 KB. With the latest GenFw changes in place (which sets
PE/COFF section alignment to the largest ELF input section alignment
it encounters), the small C model works correctly since the PE/COFF
loaders adhere to the PE/COFF section alignment. As a bonus, the ELF
and PE/COFF images will be laid out identically in memory, so all the
recalculation arithmetic becomes unnecessary (although it probably
makes sense to perform some checks
here)
If I add support in 'MdePkg/Library/BasePeCoffLib' to prevent the image
loading if the .text sections are not aligned on 4K when these page-relative
relocations are used, would you consider this patchset?
Post by Olivier Martin
In practical this error should never be exposed as AllocatePages() allocate
the buffer on a 4K boundary.
Post by Olivier Martin
The downside, of course, is that 4 KB alignment for both .text and
.data wastes a lot of space: 3.5 KB only for the padding between the
PE/COFF header and the start of .text, and 2 KB on average between .text
and .data.
Post by Olivier Martin
Due to the compression of non-XIP binaries, this is not such a
penalty, but for XIP it is prohibitive (even if these typically don't
have a .data section)
I am going to have a look at GenFv to figure out if there is some way
to work around this, i.e., drop the PE/COFF headers or move them in
some way.
Post by Olivier Martin
In the mean time, I think this patch is good except the first hunk.
The small model relocation arithmetic can be merged separately, I
think, and the logic and policies around how and when to relocate
PE/COFF images can be addressed in a followup patch.
Sorry, I am not sure to understand which part of the patch you would like
me to split...
My general point is that such relocations should only be allowed if the section
alignment is at least 4 KB. This results in bigger files generally, so I have
already implemented support in GenFw for smaller file alignment if the
section alignment is >= 4 KB (this is allowed by the PE/COFF spec) Next step is
to massage GenFv to allow such images if it manages to place it such that the
section alignment is met for all sections it contains. I think this may be doable
but I haven't managed yet. It would also require a separate LD overlay script
to put all input section into .text (since XIP modules shouldn't have writable
data anyway). This should greatly reduce the bloat in TE images with 4 KB
section alignment.
I quite dislike the idea of creating binaries that happen to work simply
because we know they should be loaded at a certain alignment that is not
communicated via its metadata.
So my position is that the first hunk should be dropped, and instead, the
patch should ensure that these relocations are only encountered in binaries
that have sufficient section alignment, and error out otherwise. For now,
that will result in bigger XIP binaries when building with LLVM, and hopefully
we can fix that later. I am quite eager to enable the small C model on GCC as
well, which obviously suffers from the same problems.
--
Ard.
Post by Olivier Martin
Post by Olivier Martin
---
BaseTools/Source/C/Common/BasePeCoff.c | 14 +++
BaseTools/Source/C/Common/PeCoffLib.h | 13 +++
BaseTools/Source/C/Common/PeCoffLoaderEx.c | 58 +++++++++++
BaseTools/Source/C/GenFw/Elf64Convert.c | 159
+++++++++++++++++++++++------
Post by Olivier Martin
BaseTools/Source/C/GenFw/elf_common.h | 4 +
5 files changed, 215 insertions(+), 33 deletions(-)
diff --git a/BaseTools/Source/C/Common/BasePeCoff.c
b/BaseTools/Source/C/Common/BasePeCoff.c
Post by Olivier Martin
index afb45df..e1401f2 100644
--- a/BaseTools/Source/C/Common/BasePeCoff.c
+++ b/BaseTools/Source/C/Common/BasePeCoff.c
RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN)
RelocBase
Post by Olivier Martin
+ (UINTN) RelocDir->Size - 1);
Post by Olivier Martin
}
+ // In order for page relative code relocations to work on AArch64 we
need to
Post by Olivier Martin
+ // ensure that any address adjustment to images are 4k page aligned.
The page
Post by Olivier Martin
+ // relative relocations are processed at build time as we do not have
enough
Post by Olivier Martin
+ // information at runtime to recalculate them.
+ // The PE/COFF Base relocation types do not have a matching type to
describe
Post by Olivier Martin
+ // page relative relocations so we do not know if they may be present
in
Post by Olivier Martin
the
Post by Olivier Martin
+ // images. We must assume they are present and ensure the image is
properly
Post by Olivier Martin
+ // aligned to keep these relocations valid.
+ if (ImageContext->Machine == EFI_IMAGE_MACHINE_AARCH64) {
+ if ((Adjust & 0xfff) != 0x0) {
+ return RETURN_LOAD_ERROR;
+ }
+ }
+
//
// Run the relocation information and apply the fixups
//
diff --git a/BaseTools/Source/C/Common/PeCoffLib.h
b/BaseTools/Source/C/Common/PeCoffLib.h
Post by Olivier Martin
index b56dd75..2f8feb7 100644
--- a/BaseTools/Source/C/Common/PeCoffLib.h
+++ b/BaseTools/Source/C/Common/PeCoffLib.h
@@ -205,6 +205,19 @@ ThumbMovwMovtImmediatePatch (
IN UINT32 Address
);
+/**
+ Update AArch64 instruction immediate address data.
+
+
+**/
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Val
+ );
#endif
diff --git a/BaseTools/Source/C/Common/PeCoffLoaderEx.c
b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
Post by Olivier Martin
index b7b7227..3864391 100644
--- a/BaseTools/Source/C/Common/PeCoffLoaderEx.c
+++ b/BaseTools/Source/C/Common/PeCoffLoaderEx.c
@@ -466,6 +466,64 @@ PeCoffLoaderRelocateArmImage (
return RETURN_SUCCESS;
}
+
+/**
+ Update AArch64 instruction immediate address data.
+
value
Post by Olivier Martin
Post by Olivier Martin
+ to preserve sign extension where needed. Some
+ instructions can have positive and negative values.
+
+**/
+// The values below are used to match instructions based on the
architecture encoding
Post by Olivier Martin
+// Don't support shifted imm12 for ADD instructions. Set as 0 in MASK
and
Post by Olivier Martin
INST
Post by Olivier Martin
+#define AARCH64_ADD_MASK 0x1FC00000
+#define AARCH64_ADD_INST 0x11000000
+#define AARCH64_ADD_IMM 0x003FFC00
+#define IS_AARCH64_ADD(x) ((x & AARCH64_ADD_MASK) ==
AARCH64_ADD_INST)
Post by Olivier Martin
+#define AARCH64_ADRP_MASK 0x9f000000
+#define AARCH64_ADRP_INST 0x90000000
+#define AARCH64_ADRP_IMM 0x60FFFFE0
+#define IS_AARCH64_ADRP(x) ((x & AARCH64_ADRP_MASK) ==
AARCH64_ADRP_INST)
Post by Olivier Martin
+#define AARCH64_LDST_MASK 0x3b000000
+#define AARCH64_LDST_INST 0x39000000
+#define AARCH64_LDST_IMM 0x003FFC00
+#define IS_AARCH64_LDST(x) ((x & AARCH64_LDST_MASK) ==
AARCH64_LDST_INST)
Post by Olivier Martin
+
+RETURN_STATUS
+EFIAPI
+Aarch64ImmediatePatch (
+ IN OUT UINT32 *Instruction,
+ IN INT32 Value
+ )
+{
+ UINT32 Patch;
+ RETURN_STATUS Status;
+
+ Status = RETURN_UNSUPPORTED;
+
+ // Disassemble and update the instruction
+ if (IS_AARCH64_ADD (*Instruction)) {
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_ADD_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_ADRP (*Instruction)) {
+ Patch = ((Value & 0x3) << 29) | (((Value & 0x1FFFFC) >> 2) << 5);
+ *Instruction = (*Instruction & ~AARCH64_ADRP_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ } else if (IS_AARCH64_LDST (*Instruction)) {
+ // Relocation types LDST8,16,32,64,128 specify different bitsizes.
+ // The Calling function knows the relocation type and has already
masked and
Post by Olivier Martin
+ // scaled the address as needed.
+ Patch = Value << 10;
+ *Instruction = (*Instruction & ~AARCH64_LDST_IMM) | Patch;
+ Status = RETURN_SUCCESS;
+ }
+
+ return Status;
+}
+
RETURN_STATUS
PeCoffLoaderRelocateAArch64Image (
IN UINT16 *Reloc,
diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c
b/BaseTools/Source/C/GenFw/Elf64Convert.c
Post by Olivier Martin
index d2becf1..355398f 100644
--- a/BaseTools/Source/C/GenFw/Elf64Convert.c
+++ b/BaseTools/Source/C/GenFw/Elf64Convert.c
@@ -709,56 +709,148 @@ WriteSections64 (
Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64
relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
Post by Olivier Martin
}
} else if (mEhdr->e_machine == EM_AARCH64) {
-
- // AARCH64 GCC uses RELA relocation, so all relocations have to be
fixed up.
Post by Olivier Martin
- // As opposed to ARM32 using REL.
-
+ // For ease of use specify relocations in terms of P, S and A as
+ // described the AArch64 ELF specification
+ UINT64 P, S;
+ INT64 A;
+ RETURN_STATUS Status;
+
+ // P - Address of the 'Place' being relocated
+ // S - Address of the Symbol
+ // A - The Addend for the relocation
+ P = (UINT64)(SecOffset + (Rel->r_offset - SecShdr->sh_addr));
+ S = (UINT64)(Sym->st_value - SymShdr->sh_addr +
mCoffSectionsOffset[Sym->st_shndx]);
Post by Olivier Martin
+ A = (INT64)(Rel->r_addend);
+
+ // Some versions of the AArch64 GCC linker does not update the
ELF
Post by Olivier Martin
Post by Olivier Martin
+ // relocations properly when doing the final static link. For this
+ // reason we do not fully recalculate the relocations that it might
+ // use with the Large memory model. We rely on the assumption
that the
Post by Olivier Martin
+ // code sections affected by these relocations are not reordered
going
Post by Olivier Martin
+ // from ELF to PE/COFF and a simple offset adjustment is
sufficient.
Post by Olivier Martin
Post by Olivier Martin
+ // In the case of the ARM LLVM based compiler the relocation
+ // information is correct and as such we can use the small memory
+ // model and recalculate the relocations based on 'Place', 'Symbol'
+ // and 'Addend' information. At some point in the future this
should
Post by Olivier Martin
Post by Olivier Martin
+ // be be done for AArch64 GCC as well.
switch (ELF_R_TYPE(Rel->r_info)) {
+ // Ideally we should recalculate all relocations in case the code
+ // sections moved around, but in some AArch64 GCC versions this
is
Post by Olivier Martin
Post by Olivier Martin
+ // currently not working correctly.
+
+ // Relative relocations
- if (Rel->r_addend != 0 ) { /* TODO */
R_AARCH64_ADR_PREL_LO21 Need to fixup with addend!.");
Post by Olivier Martin
- }
+ // GCC with Large memory model uses this one. Leave as is for
now.
Post by Olivier Martin
Post by Olivier Martin
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_ADR_PREL_LO21: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
break;
- if (Rel->r_addend != 0 ) { /* TODO */
R_AARCH64_CONDBR19
Post by Olivier Martin
Need to fixup with addend!.");
Post by Olivier Martin
- }
+ // GCC with Large memory model uses this one. Leave as is for
now.
Post by Olivier Martin
Post by Olivier Martin
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CONDBR19: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
break;
- if (Rel->r_addend != 0 ) { /* TODO */
R_AARCH64_LD_PREL_LO19 Need to fixup with addend!.");
Post by Olivier Martin
- }
+ // GCC with Large memory model uses this one. Leave as is for
now.
Post by Olivier Martin
Post by Olivier Martin
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_LD_PREL_LO19: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
break;
+ // GCC with Large memory model uses this one. Leave as is for
now.
Post by Olivier Martin
Post by Olivier Martin
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_CALL26: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ break;
+
- if (Rel->r_addend != 0 ) {
- // Some references to static functions sometime start at the
base
Post by Olivier Martin
of .text + addend.
Post by Olivier Martin
- // It is safe to ignore these relocations because they patch a `BL`
instructions that
Post by Olivier Martin
- // contains an offset from the instruction itself and there is only
a
Post by Olivier Martin
single .text section.
Post by Olivier Martin
- // So we check if the symbol is a "section symbol"
- if (ELF64_ST_TYPE (Sym->st_info) == STT_SECTION) {
- break;
- }
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26
Need to fixup with addend!.");
Post by Olivier Martin
- }
+ // GCC with Large memory model uses this one. Leave as is for
now.
Post by Olivier Martin
Post by Olivier Martin
+ // Reloc = (S+A-P)
+ VerboseMsg ("R_AARCH64_JUMP26: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
break;
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s
unsupported
Post by Olivier Martin
ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.",
mInImageName);
Post by Olivier Martin
+ // We need to fully recalculate this relocation. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = PAGE(S+A) - PAGE(P) ; Page = 4k
+ VerboseMsg ("R_AARCH64_ADR_PREL_PG_HI21: Targ =
0x%08lx,
Post by Olivier Martin
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ INT32 Tmp = R_AARCH64_PAGE (S + A) - R_AARCH64_PAGE (P);
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, Tmp / 4096);
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
break;
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s
unsupported
Post by Olivier Martin
ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.",
mInImageName);
Post by Olivier Martin
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ADD_ABS_LO12_NC: Targ = 0x%08lx,
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) &
R_AARCH64_PAGE_MASK);
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST8_ABS_LO12_NC: Targ =
0x%08lx,
Post by Olivier Martin
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, (S + A) &
R_AARCH64_PAGE_MASK);
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST16_ABS_LO12_NC: Targ =
0x%08lx,
Post by Olivier Martin
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 1 );
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST32_ABS_LO12_NC: Targ =
0x%08lx,
Post by Olivier Martin
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 2 );
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST64_ABS_LO12_NC: Targ =
0x%08lx,
Post by Olivier Martin
*Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 3 );
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
+ break;
+
+ // Used with R_AARCH64_ADR_PREL_PG_HI21. This is used with
the
Post by Olivier Martin
small memory model.
Post by Olivier Martin
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_LDST128_ABS_LO12_NC: Targ =
0x%08lx, *Targ=0x%08x\n", (UINT64)Targ, *(UINT32 *)Targ);
Post by Olivier Martin
+ Status = Aarch64ImmediatePatch ((UINT32 *)Targ, ((S + A) &
R_AARCH64_PAGE_MASK) >> 4 );
Post by Olivier Martin
+ if (Status != RETURN_SUCCESS) {
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s Patching
ELF
Post by Olivier Martin
EM_AARCH64 relocation failed.", mInImageName);
Post by Olivier Martin
+ }
break;
// Absolute relocations.
+ // GCC with Large memory model uses this one. Don't recalculate
the
Post by Olivier Martin
+ // relocation, just do the section offset adjustment. This
assumes
Post by Olivier Martin
Post by Olivier Martin
+ // the relevant sections are not getting reordered.
+ // Reloc = (S+A)
+ VerboseMsg ("R_AARCH64_ABS64: Targ = 0x%08lx,
*Targ=0x%08lx\n", (UINT64)Targ, *(UINT64 *)Targ);
Post by Olivier Martin
+
+ // *Targ = *Targ - elf-section-addr[bss] + coff-section-addr[bss]
*(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr +
mCoffSectionsOffset[Sym->st_shndx];
Post by Olivier Martin
break;
@@ -838,17 +930,18 @@ WriteRelocations64 (
break;
+ // These relocations are used together
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s
unsupported ELF EM_AARCH64 relocation
R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);
Post by Olivier Martin
- break;
-
- // TODO : AArch64 'small' memory model.
- Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s
unsupported ELF EM_AARCH64 relocation
R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);
Post by Olivier Martin
break;
+ // Write DIR64 to the PE/COFF reloc fixup list
CoffAddFixup(
(UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]
+ (Rel->r_offset - SecShdr->sh_addr)),
diff --git a/BaseTools/Source/C/GenFw/elf_common.h
b/BaseTools/Source/C/GenFw/elf_common.h
Post by Olivier Martin
index 766d0e4..d9057b6 100644
--- a/BaseTools/Source/C/GenFw/elf_common.h
+++ b/BaseTools/Source/C/GenFw/elf_common.h
@@ -673,6 +673,10 @@ typedef struct {
#define R_AARCH64_TLS_DTPREL32 1031 /* DTPREL(S+A)
*/
Post by Olivier Martin
Post by Olivier Martin
#define R_AARCH64_TLS_DTPMOD32 1032 /* LDM(S) */
#define R_AARCH64_TLS_TPREL32 1033 /* DTPREL(S+A)
*/
Post by Olivier Martin
Post by Olivier Martin
+/* AArch64 page relative relocations use 4k pages. */
+#define R_AARCH64_PAGE_SIZE 0x1000
+#define R_AARCH64_PAGE_MASK 0xfffUL
+#define R_AARCH64_PAGE(x) ((x) &
~R_AARCH64_PAGE_MASK)
Post by Olivier Martin
#define R_ALPHA_NONE 0 /* No reloc */
#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
--
2.1.1
-- IMPORTANT NOTICE: The contents of this email and any attachments are
confidential and may also be privileged. If you are not the intended recipient,
please notify the sender immediately and do not disclose the contents to any
other person, use it for any purpose, or store or copy the information in any
medium. Thank you.
Post by Olivier Martin
ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ,
Registered in England & Wales, Company No: 2557590
Post by Olivier Martin
ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1
9NJ, Registered in England & Wales, Company No: 2548782
-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2557590
ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2548782
Loading...