diff options
author | Ard Biesheuvel <ard.biesheuvel@linaro.org> | 2015-12-18 06:52:50 +0000 |
---|---|---|
committer | vanjeff <vanjeff@Edk2> | 2015-12-18 06:52:50 +0000 |
commit | 7f33c1d949d8ce1f1bff57a230d42d1c2ac1b1f8 (patch) | |
tree | 036fa8a8da10fa68c4351b7f945793ee648d1b8f /BaseTools/Source/C/GenFw/Elf32Convert.c | |
parent | 8bc5c95c550103317b739d3d620b189d03121062 (diff) | |
download | edk2-platforms-7f33c1d949d8ce1f1bff57a230d42d1c2ac1b1f8.tar.xz |
BaseTools/GenFw RVCT: fix relocation processing of PT_DYNAMIC sections
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.
(Sync patch r19236 from main trunk.)
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/branches/UDK2015@19383 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'BaseTools/Source/C/GenFw/Elf32Convert.c')
-rw-r--r-- | BaseTools/Source/C/GenFw/Elf32Convert.c | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/BaseTools/Source/C/GenFw/Elf32Convert.c b/BaseTools/Source/C/GenFw/Elf32Convert.c index 469394540e..eede645769 100644 --- a/BaseTools/Source/C/GenFw/Elf32Convert.c +++ b/BaseTools/Source/C/GenFw/Elf32Convert.c @@ -804,9 +804,7 @@ WriteRelocations32 ( UINTN RelSize;
UINTN RelOffset;
UINTN K;
- UINT8 *Targ;
Elf32_Phdr *DynamicSegment;
- Elf32_Phdr *TargetSegment;
for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {
Elf_Shdr *RelShdr = GetShdrByIndex(Index);
@@ -957,6 +955,31 @@ WriteRelocations32 ( Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName);
}
+ for (Index = 0; Index < mEhdr->e_shnum; Index++) {
+ Elf_Shdr *shdr = GetShdrByIndex(Index);
+
+ //
+ // The PT_DYNAMIC section contains DT_REL relocations whose r_offset
+ // field is relative to the base of a segment (or the entire image),
+ // and not to the base of an ELF input section as is the case for
+ // SHT_REL sections. This means that we cannot fix up such relocations
+ // unless we cross-reference ELF sections and segments, considering
+ // that the output placement recorded in mCoffSectionsOffset[] is
+ // section based, not segment based.
+ //
+ // Fortunately, there is a simple way around this: we require that the
+ // in-memory layout of the ELF and PE/COFF versions of the binary is
+ // identical. That way, r_offset will retain its validity as a PE/COFF
+ // image offset, and we can record it in the COFF fixup table
+ // unmodified.
+ //
+ if (shdr->sh_addr != mCoffSectionsOffset[Index]) {
+ Error (NULL, 0, 3000,
+ "Invalid", "%s: PT_DYNAMIC relocations require identical ELF and PE/COFF section offsets.",
+ mInImageName);
+ }
+ }
+
for (K = 0; K < RelSize; K += RelElementSize) {
if (DynamicSegment->p_paddr == 0) {
@@ -973,14 +996,7 @@ WriteRelocations32 ( break;
case R_ARM_RABS32:
- TargetSegment = GetPhdrByIndex (ELF32_R_SYM (Rel->r_info) - 1);
-
- // Note: r_offset in a memory address. Convert it to a pointer in the coff file.
- Targ = mCoffFile + mCoffSectionsOffset[ ELF32_R_SYM( Rel->r_info ) ] + Rel->r_offset - TargetSegment->p_vaddr;
-
- *(UINT32 *)Targ = *(UINT32 *)Targ + mCoffSectionsOffset [ELF32_R_SYM( Rel->r_info )];
-
- CoffAddFixup (mCoffSectionsOffset[ELF32_R_SYM (Rel->r_info)] + (Rel->r_offset - TargetSegment->p_vaddr), EFI_IMAGE_REL_BASED_HIGHLOW);
+ CoffAddFixup (Rel->r_offset, EFI_IMAGE_REL_BASED_HIGHLOW);
break;
default:
|