Add address of GOT + 8 in PLT + 16 and fix PLT0

On ARM targets, the jump to ld.so resolution routine is done in PLT0 by
loading the offset to the GOT found in PLT+16 and from there loading the
address in GOT+8 and jumping to it.

Currently tcc starts the first regular PLT entry at PLT+16 which thus
does not contain the offset to the GOT. This commit fixes that.

Note that calls via PLT still worked nonetheless because of some missing
dynamic tag which makes ld.so behaves as if RTLD_BIND_NOW was specified
in the environment for all executable created by tcc.
master
Thomas Preud'homme 2016-11-12 23:16:05 +08:00
parent f924d0ca96
commit 60374d01ae
1 changed files with 5 additions and 3 deletions

View File

@ -1421,11 +1421,12 @@ static unsigned long put_got_entry(TCCState *s1,
/* empty PLT: create PLT0 entry that push address of call site and
jump to ld.so resolution routine (GOT + 8) */
if (plt->data_offset == 0) {
p = section_ptr_add(plt, 16);
p = section_ptr_add(plt, 20);
write32le(p, 0xe52de004); /* push {lr} */
write32le(p+4, 0xe59fe010); /* ldr lr, [pc, #16] */
write32le(p+4, 0xe59fe004); /* ldr lr, [pc, #4] */
write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */
write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
/* p+16 is set in relocate_plt */
}
symattr->plt_offset = plt->data_offset;
@ -2151,7 +2152,8 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
#elif defined(TCC_TARGET_ARM)
int x = s1->got->sh_addr - s1->plt->sh_addr - 12;
p += 16;
write32le(s1->plt->data + 16, x - 16);
p += 20;
while (p < p_end) {
if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */
p += 4;