x86-64: Add basic shared lib support

Initial support for shared libraries on x86-64.
This commit is contained in:
Michael Matz 2014-03-31 03:45:35 +02:00
parent 5a5fee867a
commit 080ad7e62a
2 changed files with 41 additions and 37 deletions

View file

@ -802,9 +802,18 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
#elif defined(TCC_TARGET_X86_64) #elif defined(TCC_TARGET_X86_64)
case R_X86_64_64: case R_X86_64_64:
if (s1->output_type == TCC_OUTPUT_DLL) { if (s1->output_type == TCC_OUTPUT_DLL) {
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); esym_index = s1->symtab_to_dynsym[sym_index];
qrel->r_addend = *(long long *)ptr + val; qrel->r_offset = rel->r_offset;
qrel++; if (esym_index) {
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64);
qrel->r_addend = rel->r_addend;
qrel++;
break;
} else {
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
qrel->r_addend = *(long long *)ptr + val;
qrel++;
}
} }
*(long long *)ptr += val; *(long long *)ptr += val;
break; break;
@ -1013,6 +1022,7 @@ static void put_got_entry(TCCState *s1,
ElfW(Sym) *sym; ElfW(Sym) *sym;
unsigned long offset; unsigned long offset;
int *ptr; int *ptr;
struct sym_attr *symattr;
if (!s1->got) if (!s1->got)
build_got(s1); build_got(s1);
@ -1037,7 +1047,10 @@ static void put_got_entry(TCCState *s1,
got_entry_present = 1; got_entry_present = 1;
} }
alloc_sym_attr(s1, sym_index)->got_offset = s1->got->data_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;
if (s1->dynsym) { if (s1->dynsym) {
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
@ -1048,6 +1061,7 @@ static void put_got_entry(TCCState *s1,
Section *plt; Section *plt;
uint8_t *p; uint8_t *p;
int modrm; int modrm;
unsigned long relofs;
#if defined(TCC_OUTPUT_DLL_WITH_PLT) #if defined(TCC_OUTPUT_DLL_WITH_PLT)
modrm = 0x25; modrm = 0x25;
@ -1072,12 +1086,21 @@ static void put_got_entry(TCCState *s1,
put32(p + 8, PTR_SIZE * 2); put32(p + 8, PTR_SIZE * 2);
} }
/* The PLT slot refers to the relocation entry it needs
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;
p = section_ptr_add(plt, 16); p = section_ptr_add(plt, 16);
p[0] = 0xff; /* jmp *(got + x) */ p[0] = 0xff; /* jmp *(got + x) */
p[1] = modrm; p[1] = modrm;
put32(p + 2, s1->got->data_offset); put32(p + 2, s1->got->data_offset);
p[6] = 0x68; /* push $xxx */ p[6] = 0x68; /* push $xxx */
put32(p + 7, (plt->data_offset - 32) >> 1); #ifdef TCC_TARGET_X86_64
/* On x86-64, the relocation is referred to by _index_. */
put32(p + 7, relofs / sizeof (ElfW_Rel));
#else
put32(p + 7, relofs);
#endif
p[11] = 0xe9; /* jmp plt_start */ p[11] = 0xe9; /* jmp plt_start */
put32(p + 12, -(plt->data_offset)); put32(p + 12, -(plt->data_offset));
@ -1087,7 +1110,7 @@ static void put_got_entry(TCCState *s1,
if (s1->output_type == TCC_OUTPUT_EXE) if (s1->output_type == TCC_OUTPUT_EXE)
#endif #endif
offset = plt->data_offset - 16; offset = plt->data_offset - 16;
s1->sym_attrs[sym_index].has_plt_entry = 1; symattr->has_plt_entry = 1;
} }
#elif defined(TCC_TARGET_ARM) #elif defined(TCC_TARGET_ARM)
if (need_plt_entry) { if (need_plt_entry) {
@ -1109,7 +1132,7 @@ static void put_got_entry(TCCState *s1,
put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */ put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
} }
if (s1->sym_attrs[sym_index].plt_thumb_stub) { if (symattr->plt_thumb_stub) {
p = section_ptr_add(plt, 20); p = section_ptr_add(plt, 20);
put32(p, 0x4778); /* bx pc */ put32(p, 0x4778); /* bx pc */
put32(p+2, 0x46c0); /* nop */ put32(p+2, 0x46c0); /* nop */
@ -1125,27 +1148,23 @@ static void put_got_entry(TCCState *s1,
the PLT */ the PLT */
if (s1->output_type == TCC_OUTPUT_EXE) if (s1->output_type == TCC_OUTPUT_EXE)
offset = plt->data_offset - 16; offset = plt->data_offset - 16;
s1->sym_attrs[sym_index].has_plt_entry = 1; symattr->has_plt_entry = 1;
} }
#elif defined(TCC_TARGET_C67) #elif defined(TCC_TARGET_C67)
tcc_error("C67 got not implemented"); tcc_error("C67 got not implemented");
#else #else
#error unsupported CPU #error unsupported CPU
#endif #endif
/* XXX This might generate multiple syms for name. */
index = put_elf_sym(s1->dynsym, offset, index = put_elf_sym(s1->dynsym, offset,
size, info, 0, sym->st_shndx, name); size, info, 0, sym->st_shndx, name);
if (got_entry_present) { /* Create the relocation (it's against the GOT for PLT
put_elf_reloc(s1->dynsym, s1->got, and GOT relocs). */
s1->sym_attrs[sym_index].got_offset,
reloc_type, index);
return;
}
/* put a got entry */
put_elf_reloc(s1->dynsym, s1->got, put_elf_reloc(s1->dynsym, s1->got,
s1->got->data_offset, s1->got->data_offset,
reloc_type, index); reloc_type, index);
} }
/* And now create the GOT slot itself. */
ptr = section_ptr_add(s1->got, PTR_SIZE); ptr = section_ptr_add(s1->got, PTR_SIZE);
*ptr = 0; *ptr = 0;
} }
@ -1697,26 +1716,11 @@ static void export_global_syms(TCCState *s1)
s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms);
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
#if defined(TCC_OUTPUT_DLL_WITH_PLT) name = (char *) symtab_section->link->data + sym->st_name;
int type = ELFW(ST_TYPE)(sym->st_info); dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
if ((type == STT_FUNC || type == STT_GNU_IFUNC) sym->st_info, 0, sym->st_shndx, name);
&& sym->st_shndx == SHN_UNDEF) { index = sym - (ElfW(Sym) *) symtab_section->data;
int visibility = ELFW(ST_BIND)(sym->st_info); s1->symtab_to_dynsym[index] = dynindex;
put_got_entry(s1, R_JMP_SLOT, sym->st_size,
ELFW(ST_INFO)(visibility, STT_FUNC),
sym - (ElfW(Sym) *) symtab_section->data);
} else if (type == STT_OBJECT) {
put_got_entry(s1, R_X86_64_GLOB_DAT, sym->st_size, sym->st_info,
sym - (ElfW(Sym) *) symtab_section->data);
} else
#endif
{
name = (char *) symtab_section->link->data + sym->st_name;
dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
sym->st_info, 0, sym->st_shndx, name);
index = sym - (ElfW(Sym) *) symtab_section->data;
s1->symtab_to_dynsym[index] = dynindex;
}
} }
} }
} }

View file

@ -604,7 +604,7 @@ static void gcall_or_jmp(int is_jmp)
if (vtop->r & VT_SYM) { if (vtop->r & VT_SYM) {
/* relocation case */ /* relocation case */
greloc(cur_text_section, vtop->sym, greloc(cur_text_section, vtop->sym,
ind + 1, R_X86_64_PC32); ind + 1, R_X86_64_PLT32);
} else { } else {
/* put an empty PC32 relocation */ /* put an empty PC32 relocation */
put_elf_reloc(symtab_section, cur_text_section, put_elf_reloc(symtab_section, cur_text_section,