mirror of
https://github.com/frida/tinycc
synced 2024-12-24 14:06:48 +03:00
x86-64: shared libs improvement
This correctly resolves local references to global functions from shared libs to their PLT slot (instead of directly to the target symbol), so that interposition works. This is still not 100% conforming (executables don't export symbols that are also defined in linked shared libs, as they must), but normal shared lib situations work.
This commit is contained in:
parent
080ad7e62a
commit
0bd1282059
2
tcc.h
2
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
|
||||
|
70
tccelf.c
70
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
|
||||
|
Loading…
Reference in New Issue
Block a user