aboutsummaryrefslogtreecommitdiff
path: root/tccelf.c
diff options
context:
space:
mode:
Diffstat (limited to 'tccelf.c')
-rw-r--r--tccelf.c70
1 files changed, 45 insertions, 25 deletions
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