[edk2,RFC,1/4] BaseTools: AArch64: conditionally allow page-based PC relative relocations

Message ID 1435073455-3268-2-git-send-email-ard.biesheuvel@linaro.org
State New
Headers show

Commit Message

Ard Biesheuvel June 23, 2015, 3:30 p.m.
This updates GenFw's ELF conversion for AArch64 so that relocation pairs
that operate on ADRP/ADD, ADRP/LDR or ADRP/STR instruction combinations
are allowed under the following conditions:
- the relative alignment to the nearest 4 KB boundary of the target of the
  relocation must be identical between the ELF and the PE/COFF versions of
  the binary;
- the offset between the relocation target and the symbol it refers to is
  identical between the ELF and the PE/COFF versions, even if the symbol
  lives in another section.

These two conditions can be met by using a carefully crafted GNU ld script
that reflects the placement logic of GenFw. Note that such binaries need
to be loaded at a 4 KB aligned load address.

This is a preliminary step towards allowing AArch64 binaries to be built
with the standard 'small' C model.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 BaseTools/Source/C/GenFw/Elf64Convert.c | 51 +++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 41 insertions(+), 10 deletions(-)

Patch hide | download patch | download mbox

diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c b/BaseTools/Source/C/GenFw/Elf64Convert.c
index 25b90e2f7b51..2266e487cec7 100644
--- a/BaseTools/Source/C/GenFw/Elf64Convert.c
+++ b/BaseTools/Source/C/GenFw/Elf64Convert.c
@@ -734,13 +734,33 @@  WriteSections64 (
             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);
-            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);
+          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:
+            //
+            // These are static PC relative relocation pairs that will already have been resolved
+            // during static linking of the ELF shared object. So no need to do anything here if
+            // a) the original ELF .text section and the derived PE/COFF .text section are placed at
+            //    the same relative alignment with respect to the nearest 4K aligned boundary;
+            // b) the section containing the symbol that the relocation pair refers to is at
+            //    the same relative offset in both binaries;
+            // c) it is guaranteed that the load time alignment of the PE/COFF binary is
+            //    at least 4 KB.
+            //
+            // While conditions a) and b) could be met by recalculating the immediates based on
+            // the actual placement of the PE/COFF sections if their offsets and/or alignments
+            // deviate, condition c) is a necessary condition that applies universally when
+            // ADRP based symbol references are used. It thus requires the appropriate 'Align=4K'
+            // declarations in the platform .FDF.
+            //
+            if ((SecOffset % 4096) != (SecShdr->sh_addr % 4096) ||
+                (mCoffSectionsOffset[Sym->st_shndx] - SecOffset) != (SymShdr->sh_addr - SecShdr->sh_addr)) {
+              // TODO: recalculate the two immediates based on the actual placement
+              Error (NULL, 0, 3000, "Invalid", "AArch64: ADRP/ADD and ADRP/LDR pairs must retain relative sym offset and relative alignment to 4 KB!.");
+            }
             break;
 
           // Absolute relocations.
@@ -825,13 +845,24 @@  WriteRelocations64 (
               break;
 
             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);
+              break;
+
+            case R_AARCH64_LDST8_ABS_LO12_NC:
+              break;
+
+            case R_AARCH64_LDST16_ABS_LO12_NC:
+              break;
+
+            case R_AARCH64_LDST32_ABS_LO12_NC:
+              break;
+
+            case R_AARCH64_LDST64_ABS_LO12_NC:
+              break;
+
+            case R_AARCH64_LDST128_ABS_LO12_NC:
               break;
 
             case R_AARCH64_ABS64: