From 60374d01ae56e59308d1b5441bc1986295507ec6 Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Sat, 12 Nov 2016 23:16:05 +0800 Subject: [PATCH] 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. --- tccelf.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tccelf.c b/tccelf.c index 75bf05f..e9fa229 100644 --- a/tccelf.c +++ b/tccelf.c @@ -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;