Re: [PATCH v2 2/7] BaseTools-GenFw:Add new x86_64 Elf relocation types for PIC/PIE code


Ard Biesheuvel
 

(adding back our friends on cc)

On 1 August 2016 at 12:36, Shi, Steven <steven.shi@intel.com> wrote:
On 1 August 2016 at 12:16, Shi, Steven <steven.shi@intel.com> wrote:
OK, another example:

pie.s:

.globl foo
foo:
pushq n@GOTPCREL(%rip)
popq %rax
ret

.globl bar
bar:
pushq n@GOTPCREL(%rip)
popq %rax
ret

.globl n
n:
.quad 0

compile and link using

gcc -c -o pie.o /tmp/pie.s
ld -q -o pie pie.o -e foo

gives me

Relocation section '.rela.text' at offset 0x260 contains 2 entries:
Offset Info Type Sym. Value Sym. Name + Addend
0000004000b2 000700000009 R_X86_64_GOTPCREL 00000000004000be
n -
4
0000004000b9 000700000009 R_X86_64_GOTPCREL 00000000004000be
n -
4

Here, pie is a fully linked binary.
[Steven]: In this example, there are two R_X86_64_GOTPCREL relocation
address in the .text section need to fix up with same symbol runtime address,
these two relocation addresses are not same, and every relocation address
will be fixed up once. I don't see the problem of "Having multiple fixups for
the same symbol in the .reloc section", and current GenFw code should has
no problem on this example.
How many times will your code call CoffAddFixup() for the address of n?
[Steven]: My understanding is the n address (6000c8) is not a GOTPCREL relocation in .text section, but the 4000b2 and 4000b2 are GOTPCREL relocation in .text section. My CoffAddFixup() will only call twice for 4000b2 and 4000b2, but not for n address (6000c8).

Disassembly of section .text:

00000000004000b0 <foo>:
4000b0: ff 35 12 00 20 00 pushq 0x200012(%rip) # 6000c8 <n+0x200008>
4000b6: 58 pop %rax
4000b7: c3 retq

00000000004000b8 <bar>:
4000b8: ff 35 0a 00 20 00 pushq 0x20000a(%rip) # 6000c8 <n+0x200008>
4000be: 58 pop %rax
4000bf: c3 retq

00000000004000c0 <n>:
...
CoffAddFixup() must be used for absolute symbol references only. These
instructions contain relative symbol references, which are
recalculated in WriteSections64().

The only absolute symbol reference is the GOT entry for 'n', and your
code (in WriteRelocations64()) calculates the address of the GOT entry
(which is always in .text BTW) and adds a fixup for it, i.e.,

+ CoffAddFixup(
+ (UINT32)(UINTN)((UINT64)
mCoffSectionsOffset[RelShdr->sh_info] + GoTPcRelPtrOffset),
+ EFI_IMAGE_REL_BASED_DIR64);

This code adds a fixup to the PE/COFF .reloc section for the GOT entry
containing the address of 'n', and the instructions perform a IP
relative load of the contents of the GOT entry to retrieve the address
of 'n'.

By adding two fixups, the PE/COFF loader will apply the load offset
twice, resulting in an incorrect value.

--
Ard.

Join devel@edk2.groups.io to automatically receive all group messages.