There is a special case in the 32-bit ElfConvert code where ARM's
.data is not aligned to section alignment. This is needed to deal
with an ARM RVCT specific size optimization that results in sections
being misaligned with respect to their own alignment. The contents
of these sections are laid out such that all contained objects will
appear at their correct respective alignments provided that the
misalignment of the section as a whole is preserved. If this turns out
not to be the case, GenFw gives an error and aborts.

Since not aligning .data to the PE/COFF section alignment is a violation
of the PE/COFF spec, we must remove the special case. In order to ensure
that sections that have received the RVCT treatment are still placed
correctly, preserve the misalignment explicitly, by advancing the
PE/COFF output pointer to an appropriately misaligned value before
emitting the section.

Since this may result in the relative offset of the .text and .data
sections to change, add an explicit check to the relocation handling
code to ensure that all cross-section relative symbol references are
still correct.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <[email protected]>
Tested-by: Michael Zimmermann <[email protected]>
---
 BaseTools/Source/C/GenFw/Elf32Convert.c | 67 +++++++++++++-------
 1 file changed, 43 insertions(+), 24 deletions(-)

diff --git a/BaseTools/Source/C/GenFw/Elf32Convert.c 
b/BaseTools/Source/C/GenFw/Elf32Convert.c
index e1b92ebd713e..ed7d3609de08 100644
--- a/BaseTools/Source/C/GenFw/Elf32Convert.c
+++ b/BaseTools/Source/C/GenFw/Elf32Convert.c
@@ -331,21 +331,9 @@ ScanSections32 (
         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
           // if the section address is aligned we must align PE/COFF
           mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & 
~(shdr->sh_addralign - 1);
-        } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % 
shdr->sh_addralign)) {
-          // ARM RVCT tools have behavior outside of the ELF specification to 
try
-          // and make images smaller.  If sh_addr is not aligned to 
sh_addralign
-          // then the section needs to preserve sh_addr MOD sh_addralign.
-          // Normally doing nothing here works great.
-          Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");
         }
       }
 
-      /* Relocate entry.  */
-      if ((mEhdr->e_entry >= shdr->sh_addr) &&
-          (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
-        CoffEntry = mCoffOffset + mEhdr->e_entry - shdr->sh_addr;
-      }
-
       //
       // Set mTextOffset with the offset of the first '.text' section
       //
@@ -354,6 +342,24 @@ ScanSections32 (
         FoundSection = TRUE;
       }
 
+      if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1) &&
+          (shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % 
shdr->sh_addralign)) {
+        // ARM RVCT tools have behavior outside of the ELF specification to try
+        // and make images smaller.  If sh_addr is not aligned to sh_addralign
+        // then the section needs to preserve sh_addr MOD sh_addralign.
+        if ((shdr->sh_addr % shdr->sh_addralign) < (mCoffOffset % 
shdr->sh_addralign)) {
+          mCoffOffset += shdr->sh_addralign - 1;
+        }
+        mCoffOffset &= ~(shdr->sh_addralign - 1);
+        mCoffOffset |= shdr->sh_addr % shdr->sh_addralign;
+      }
+
+      /* Relocate entry.  */
+      if ((mEhdr->e_entry >= shdr->sh_addr) &&
+          (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
+        CoffEntry = mCoffOffset + mEhdr->e_entry - shdr->sh_addr;
+      }
+
       mCoffSectionsOffset[i] = mCoffOffset;
       mCoffOffset += shdr->sh_size;
       SectionCount ++;
@@ -367,9 +373,7 @@ ScanSections32 (
 
   mDebugOffset = mCoffOffset;
 
-  if (mEhdr->e_machine != EM_ARM) {
-    mCoffOffset = CoffAlign(mCoffOffset);
-  }
+  mCoffOffset = CoffAlign(mCoffOffset);
 
   if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {
     Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text 
section. Source level debug might not work correctly.", mInImageName);
@@ -389,12 +393,6 @@ ScanSections32 (
         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
           // if the section address is aligned we must align PE/COFF
           mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & 
~(shdr->sh_addralign - 1);
-        } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % 
shdr->sh_addralign)) {
-          // ARM RVCT tools have behavior outside of the ELF specification to 
try
-          // and make images smaller.  If sh_addr is not aligned to 
sh_addralign
-          // then the section needs to preserve sh_addr MOD sh_addralign.
-          // Normally doing nothing here works great.
-          Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");
         }
       }
 
@@ -406,6 +404,18 @@ ScanSections32 (
         FoundSection = TRUE;
       }
 
+      if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1) &&
+          (shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % 
shdr->sh_addralign)) {
+        // ARM RVCT tools have behavior outside of the ELF specification to try
+        // and make images smaller.  If sh_addr is not aligned to sh_addralign
+        // then the section needs to preserve sh_addr MOD sh_addralign.
+        if ((shdr->sh_addr % shdr->sh_addralign) < (mCoffOffset % 
shdr->sh_addralign)) {
+          mCoffOffset += shdr->sh_addralign - 1;
+        }
+        mCoffOffset &= ~(shdr->sh_addralign - 1);
+        mCoffOffset |= shdr->sh_addr % shdr->sh_addralign;
+      }
+
       mCoffSectionsOffset[i] = mCoffOffset;
       mCoffOffset += shdr->sh_size;
       SectionCount ++;
@@ -719,7 +729,7 @@ WriteSections32 (
           switch (ELF32_R_TYPE(Rel->r_info)) {
           case R_ARM_RBASE:
             // No relocation - no action required
-            // break skipped
+            break;
 
           case R_ARM_PC24:
           case R_ARM_XPC25:
@@ -756,8 +766,17 @@ WriteSections32 (
           case R_ARM_TLS_GD32:
           case R_ARM_TLS_LDM32:
           case R_ARM_TLS_IE32:
-            // Thease are all PC-relative relocations and don't require 
modification
-            // GCC does not seem to have the concept of a application that 
just needs to get relocated.
+            //
+            // These are all PC-relative relocations and don't require 
modification
+            // as long as the relative offset between the section containing 
the
+            // place and the section containing the symbol has been preserved
+            // by the PE/COFF conversion.
+            //
+            if ((SymShdr->sh_addr - SecShdr->sh_addr) !=
+                (mCoffSectionsOffset[Sym->st_shndx] - SecOffset)) {
+              Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s ARM 
relative relocations require identical ELF and PE/COFF section offsets",
+              mInImageName);
+            }
             break;
 
           case R_ARM_THM_MOVW_ABS_NC:
-- 
1.9.1

_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to