]> git.proxmox.com Git - mirror_edk2.git/commitdiff
BaseTools/GenFw RVCT: fix relocation processing of PT_DYNAMIC sections
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Mon, 14 Dec 2015 07:56:02 +0000 (07:56 +0000)
committerabiesheuvel <abiesheuvel@Edk2>
Mon, 14 Dec 2015 07:56:02 +0000 (07:56 +0000)
Unlike GNU ld, which can be instructed to emit symbol based static
relocations into fully linked binaries using the --emit-relocs command
line switch, the RVCT armlink tool can only emit dynamic relocations
into the PT_DYNAMIC segment.

This has two consequences
. we can only identify absolute relocations, so there is no way to fix
  up relative relocations between sections, or check their validity in
  the PE/COFF layout
. the r_offset fields of the PT_DYNAMIC DT_REL entries are relative
  either to the base of the image or to any of its segments but *not* to
  the base of the input section that contains the location they refer
  to, and converting them to PE/COFF image offsets is non-trivial unless
  the sections are laid out in the same way in the ELF and PE/COFF
  versions of the binary.

There is really only one way to deal with this, and that is to require
that the ELF and PE/COFF versions of the binary are identical in memory.
So enforce that in the code.

Also, fix the utterly broken relocation fixup code that dereferences
ELF32_R_SYM(r_info) both as a 1-based program header index and a 0-based
section header index. If this code ever produced working binaries, it
was purely by chance.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Liming Gao <liming.gao@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19236 6f19259b-4bc3-4df7-8a09-765794883524

BaseTools/Source/C/GenFw/Elf32Convert.c

index 469394540e6afb88d533a8d3480c639bf6d7f13f..eede64576940a57be3d69c643e0f85fa4f8e0372 100644 (file)
@@ -804,9 +804,7 @@ WriteRelocations32 (
   UINTN                            RelSize;\r
   UINTN                            RelOffset;\r
   UINTN                            K;\r
-  UINT8                            *Targ;\r
   Elf32_Phdr                       *DynamicSegment;\r
-  Elf32_Phdr                       *TargetSegment;\r
 \r
   for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {\r
     Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
@@ -957,6 +955,31 @@ WriteRelocations32 (
           Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName);\r
         }\r
 \r
+        for (Index = 0; Index < mEhdr->e_shnum; Index++) {\r
+          Elf_Shdr *shdr = GetShdrByIndex(Index);\r
+\r
+          //\r
+          // The PT_DYNAMIC section contains DT_REL relocations whose r_offset\r
+          // field is relative to the base of a segment (or the entire image),\r
+          // and not to the base of an ELF input section as is the case for\r
+          // SHT_REL sections. This means that we cannot fix up such relocations\r
+          // unless we cross-reference ELF sections and segments, considering\r
+          // that the output placement recorded in mCoffSectionsOffset[] is\r
+          // section based, not segment based.\r
+          //\r
+          // Fortunately, there is a simple way around this: we require that the\r
+          // in-memory layout of the ELF and PE/COFF versions of the binary is\r
+          // identical. That way, r_offset will retain its validity as a PE/COFF\r
+          // image offset, and we can record it in the COFF fixup table\r
+          // unmodified.\r
+          //\r
+          if (shdr->sh_addr != mCoffSectionsOffset[Index]) {\r
+            Error (NULL, 0, 3000,\r
+              "Invalid", "%s: PT_DYNAMIC relocations require identical ELF and PE/COFF section offsets.",\r
+              mInImageName);\r
+          }\r
+        }\r
+\r
         for (K = 0; K < RelSize; K += RelElementSize) {\r
 \r
           if (DynamicSegment->p_paddr == 0) {\r
@@ -973,14 +996,7 @@ WriteRelocations32 (
             break;\r
 \r
           case  R_ARM_RABS32:\r
-            TargetSegment = GetPhdrByIndex (ELF32_R_SYM (Rel->r_info) - 1);\r
-\r
-            // Note: r_offset in a memory address.  Convert it to a pointer in the coff file.\r
-            Targ = mCoffFile + mCoffSectionsOffset[ ELF32_R_SYM( Rel->r_info ) ] + Rel->r_offset - TargetSegment->p_vaddr;\r
-\r
-            *(UINT32 *)Targ = *(UINT32 *)Targ + mCoffSectionsOffset [ELF32_R_SYM( Rel->r_info )];\r
-\r
-            CoffAddFixup (mCoffSectionsOffset[ELF32_R_SYM (Rel->r_info)] + (Rel->r_offset - TargetSegment->p_vaddr), EFI_IMAGE_REL_BASED_HIGHLOW);\r
+            CoffAddFixup (Rel->r_offset, EFI_IMAGE_REL_BASED_HIGHLOW);\r
             break;\r
           \r
           default:\r