diff --git a/tcc.h b/tcc.h index 5ab50d6..f508097 100644 --- a/tcc.h +++ b/tcc.h @@ -522,7 +522,7 @@ typedef struct ASMOperand { struct sym_attr { unsigned long got_offset; - unsigned char has_plt_entry:1; + unsigned long plt_offset; #ifdef TCC_TARGET_ARM unsigned char plt_thumb_stub:1; #endif diff --git a/tccelf.c b/tccelf.c index 38d3e3e..7544d2e 100644 --- a/tccelf.c +++ b/tccelf.c @@ -841,8 +841,18 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) break; } } - /* fall through */ - case R_X86_64_PLT32: { + goto plt32pc32; + + case R_X86_64_PLT32: + /* We've put the PLT slot offset into r_addend when generating + it, and that's what we must use as relocation value (adjusted + by section offset of course). */ + if (s1->output_type != TCC_OUTPUT_MEMORY) + val = s1->plt->sh_addr + rel->r_addend; + /* fallthrough. */ + + plt32pc32: + { long long diff; diff = (long long)val - addr; if (diff <= -2147483647 || diff > 2147483647) { @@ -1011,13 +1021,14 @@ static void build_got(TCCState *s1) #endif } -/* put a got entry corresponding to a symbol in symtab_section. 'size' - and 'info' can be modifed if more precise info comes from the DLL */ -static void put_got_entry(TCCState *s1, - int reloc_type, unsigned long size, int info, - int sym_index) +/* put a got or plt entry corresponding to a symbol in symtab_section. 'size' + and 'info' can be modifed if more precise info comes from the DLL. + Returns offset of GOT or PLT slot. */ +static unsigned long put_got_entry(TCCState *s1, + int reloc_type, unsigned long size, int info, + int sym_index) { - int index, need_plt_entry, got_entry_present = 0; + int index, need_plt_entry; const char *name; ElfW(Sym) *sym; unsigned long offset; @@ -1038,16 +1049,16 @@ static void put_got_entry(TCCState *s1, 0; #endif - /* if a got entry already exists for that symbol, no need to add one */ - if (sym_index < s1->nb_sym_attrs && - s1->sym_attrs[sym_index].got_offset) { - if (!need_plt_entry || s1->sym_attrs[sym_index].has_plt_entry) - return; - else - got_entry_present = 1; + /* If a got/plt entry already exists for that symbol, no need to add one */ + if (sym_index < s1->nb_sym_attrs) { + if (need_plt_entry && s1->sym_attrs[sym_index].plt_offset) + return s1->sym_attrs[sym_index].plt_offset; + else if (!need_plt_entry && s1->sym_attrs[sym_index].got_offset) + return s1->sym_attrs[sym_index].got_offset; } symattr = alloc_sym_attr(s1, sym_index); + /* Only store the GOT offset if it's not generated for the PLT entry. */ if (!need_plt_entry) symattr->got_offset = s1->got->data_offset; @@ -1090,6 +1101,7 @@ static void put_got_entry(TCCState *s1, via offset. The reloc entry is created below, so its offset is the current data_offset. */ relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; + symattr->plt_offset = plt->data_offset; p = section_ptr_add(plt, 16); p[0] = 0xff; /* jmp *(got + x) */ p[1] = modrm; @@ -1104,13 +1116,11 @@ static void put_got_entry(TCCState *s1, p[11] = 0xe9; /* jmp plt_start */ put32(p + 12, -(plt->data_offset)); - /* the symbol is modified so that it will be relocated to - the PLT */ -#if !defined(TCC_OUTPUT_DLL_WITH_PLT) - if (s1->output_type == TCC_OUTPUT_EXE) -#endif - offset = plt->data_offset - 16; - symattr->has_plt_entry = 1; + /* If this was an UNDEF symbol set the offset in the + dynsymtab to the PLT slot, so that PC32 relocs to it + can be resolved. */ + if (sym->st_shndx == SHN_UNDEF) + offset = plt->data_offset - 16; } #elif defined(TCC_TARGET_ARM) if (need_plt_entry) { @@ -1132,6 +1142,7 @@ static void put_got_entry(TCCState *s1, put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */ } + symattr->plt_offset = plt->data_offset; if (symattr->plt_thumb_stub) { p = section_ptr_add(plt, 20); put32(p, 0x4778); /* bx pc */ @@ -1148,7 +1159,6 @@ static void put_got_entry(TCCState *s1, the PLT */ if (s1->output_type == TCC_OUTPUT_EXE) offset = plt->data_offset - 16; - symattr->has_plt_entry = 1; } #elif defined(TCC_TARGET_C67) tcc_error("C67 got not implemented"); @@ -1167,6 +1177,10 @@ static void put_got_entry(TCCState *s1, /* And now create the GOT slot itself. */ ptr = section_ptr_add(s1->got, PTR_SIZE); *ptr = 0; + if (need_plt_entry) + return symattr->plt_offset; + else + return symattr->got_offset; } /* build GOT and PLT entries */ @@ -1281,6 +1295,7 @@ ST_FUNC void build_got_entries(TCCState *s1) build_got(s1); if (type == R_X86_64_GOT32 || type == R_X86_64_GOTPCREL || type == R_X86_64_PLT32) { + unsigned long ofs; sym_index = ELFW(R_SYM)(rel->r_info); sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; /* look at the symbol got offset. If none, then add one */ @@ -1288,8 +1303,13 @@ ST_FUNC void build_got_entries(TCCState *s1) reloc_type = R_X86_64_GLOB_DAT; else reloc_type = R_X86_64_JUMP_SLOT; - put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, - sym_index); + ofs = put_got_entry(s1, reloc_type, sym->st_size, + sym->st_info, sym_index); + if (type == R_X86_64_PLT32 + && s1->output_type != TCC_OUTPUT_MEMORY) + /* We store the place of the generated PLT slot + in our addend. */ + rel->r_addend += ofs; } break; #else