PLT generation fix

tcc-xref
bellard 2003-04-13 14:38:05 +00:00
parent d6819c2c36
commit c2e6daafc1
1 changed files with 68 additions and 46 deletions

114
tccelf.c
View File

@ -433,7 +433,7 @@ static void relocate_syms(TCCState *s1, int do_resolve)
} }
} }
/* relocate a given section (CPU dependant) */ /* relocate a given section (CPU dependent) */
static void relocate_section(TCCState *s1, Section *s) static void relocate_section(TCCState *s1, Section *s)
{ {
Section *sr; Section *sr;
@ -581,7 +581,7 @@ static void put_got_offset(TCCState *s1, int index, unsigned long val)
} }
/* XXX: suppress that */ /* XXX: suppress that */
static void put32(unsigned char *p, unsigned int val) static void put32(unsigned char *p, uint32_t val)
{ {
p[0] = val; p[0] = val;
p[1] = val >> 8; p[1] = val >> 8;
@ -589,6 +589,11 @@ static void put32(unsigned char *p, unsigned int val)
p[3] = val >> 24; p[3] = val >> 24;
} }
static uint32_t get32(unsigned char *p)
{
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
static void build_got(TCCState *s1) static void build_got(TCCState *s1)
{ {
unsigned char *ptr; unsigned char *ptr;
@ -632,10 +637,43 @@ static void put_got_entry(TCCState *s1,
sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
name = symtab_section->link->data + sym->st_name; name = symtab_section->link->data + sym->st_name;
offset = sym->st_value; offset = sym->st_value;
/* NOTE: we put temporarily the got offset */
if (reloc_type == R_386_JMP_SLOT) { if (reloc_type == R_386_JMP_SLOT) {
s1->nb_plt_entries++; Section *plt;
offset = s1->got->data_offset; uint8_t *p;
int modrm;
/* if we build a DLL, we add a %ebx offset */
if (s1->output_type == TCC_OUTPUT_DLL)
modrm = 0xa3;
else
modrm = 0x25;
/* add a PLT entry */
plt = s1->plt;
if (plt->data_offset == 0) {
/* first plt entry */
p = section_ptr_add(plt, 16);
p[0] = 0xff; /* pushl got + 4 */
p[1] = modrm + 0x10;
put32(p + 2, 4);
p[6] = 0xff; /* jmp *(got + 8) */
p[7] = modrm;
put32(p + 8, 8);
}
p = section_ptr_add(plt, 16);
p[0] = 0xff; /* jmp *(got + x) */
p[1] = modrm;
put32(p + 2, s1->got->data_offset);
p[6] = 0x68; /* push $xxx */
put32(p + 7, (plt->data_offset - 32) >> 1);
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 (s1->output_type == TCC_OUTPUT_EXE)
offset = plt->data_offset - 16;
} }
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);
@ -847,7 +885,7 @@ int tcc_output_file(TCCState *s1, const char *filename)
Section *strsec, *s; Section *strsec, *s;
Elf32_Shdr shdr, *sh; Elf32_Shdr shdr, *sh;
Elf32_Phdr *phdr, *ph; Elf32_Phdr *phdr, *ph;
Section *interp, *plt, *dynamic, *dynstr; Section *interp, *dynamic, *dynstr;
unsigned long saved_dynamic_data_offset; unsigned long saved_dynamic_data_offset;
Elf32_Sym *sym; Elf32_Sym *sym;
int type, file_type; int type, file_type;
@ -863,7 +901,6 @@ int tcc_output_file(TCCState *s1, const char *filename)
section_order = NULL; section_order = NULL;
interp = NULL; interp = NULL;
dynamic = NULL; dynamic = NULL;
plt = NULL; /* avoid warning */
dynstr = NULL; /* avoid warning */ dynstr = NULL; /* avoid warning */
saved_dynamic_data_offset = 0; /* avoid warning */ saved_dynamic_data_offset = 0; /* avoid warning */
@ -898,8 +935,9 @@ int tcc_output_file(TCCState *s1, const char *filename)
dynamic->sh_entsize = sizeof(Elf32_Dyn); dynamic->sh_entsize = sizeof(Elf32_Dyn);
/* add PLT */ /* add PLT */
plt = new_section(s1, ".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); s1->plt = new_section(s1, ".plt", SHT_PROGBITS,
plt->sh_entsize = 4; SHF_ALLOC | SHF_EXECINSTR);
s1->plt->sh_entsize = 4;
build_got(s1); build_got(s1);
@ -998,9 +1036,6 @@ int tcc_output_file(TCCState *s1, const char *filename)
build_got_entries(s1); build_got_entries(s1);
/* update PLT/GOT sizes so that we can allocate their space */
plt->data_offset += 16 * (s1->nb_plt_entries + 1);
/* add a list of needed dlls */ /* add a list of needed dlls */
for(i = 0; i < s1->nb_loaded_dlls; i++) { for(i = 0; i < s1->nb_loaded_dlls; i++) {
DLLReference *dllref = s1->loaded_dlls[i]; DLLReference *dllref = s1->loaded_dlls[i];
@ -1191,8 +1226,6 @@ int tcc_output_file(TCCState *s1, const char *filename)
/* if dynamic section, then add corresponing program header */ /* if dynamic section, then add corresponing program header */
if (dynamic) { if (dynamic) {
int plt_offset;
unsigned char *p;
Elf32_Sym *sym_end; Elf32_Sym *sym_end;
ph = &phdr[phnum - 1]; ph = &phdr[phnum - 1];
@ -1209,49 +1242,38 @@ int tcc_output_file(TCCState *s1, const char *filename)
/* put GOT dynamic section address */ /* put GOT dynamic section address */
put32(s1->got->data, dynamic->sh_addr); put32(s1->got->data, dynamic->sh_addr);
/* compute the PLT */ /* relocate the PLT */
plt->data_offset = 0; if (file_type == TCC_OUTPUT_EXE) {
uint8_t *p, *p_end;
/* first plt entry */
p = section_ptr_add(plt, 16); p = s1->plt->data;
p[0] = 0xff; /* pushl got + 4 */ p_end = p + s1->plt->data_offset;
p[1] = 0x35; put32(p + 2, get32(p + 2) + s1->got->sh_addr);
put32(p + 2, s1->got->sh_addr + 4); put32(p + 8, get32(p + 8) + s1->got->sh_addr);
p[6] = 0xff; /* jmp *(got + 8) */ p += 16;
p[7] = 0x25; while (p < p_end) {
put32(p + 8, s1->got->sh_addr + 8); put32(p + 2, get32(p + 2) + s1->got->sh_addr);
p += 16;
/* relocation symbols in .dynsym and build PLT. */ }
plt_offset = 0; }
/* relocate symbols in .dynsym */
sym_end = (Elf32_Sym *)(s1->dynsym->data + s1->dynsym->data_offset); sym_end = (Elf32_Sym *)(s1->dynsym->data + s1->dynsym->data_offset);
for(sym = (Elf32_Sym *)s1->dynsym->data + 1; for(sym = (Elf32_Sym *)s1->dynsym->data + 1;
sym < sym_end; sym < sym_end;
sym++) { sym++) {
type = ELF32_ST_TYPE(sym->st_info);
if (sym->st_shndx == SHN_UNDEF) { if (sym->st_shndx == SHN_UNDEF) {
if (type == STT_FUNC) { /* relocate to the PLT if the symbol corresponds
/* one more entry in PLT */ to a PLT entry */
p = section_ptr_add(plt, 16); if (sym->st_value)
p[0] = 0xff; /* jmp *(got + x) */ sym->st_value += s1->plt->sh_addr;
p[1] = 0x25;
put32(p + 2, s1->got->sh_addr + sym->st_value);
p[6] = 0x68; /* push $xxx */
put32(p + 7, plt_offset);
p[11] = 0xe9; /* jmp plt_start */
put32(p + 12, -(plt->data_offset));
/* patch symbol value to point to plt */
sym->st_value = plt->sh_addr + p - plt->data;
plt_offset += 8;
}
} else if (sym->st_shndx < SHN_LORESERVE) { } else if (sym->st_shndx < SHN_LORESERVE) {
/* do symbol relocation */ /* do symbol relocation */
sym->st_value += s1->sections[sym->st_shndx]->sh_addr; sym->st_value += s1->sections[sym->st_shndx]->sh_addr;
} }
} }
/* put dynamic section entries */
/* put dynamic section entries */
dynamic->data_offset = saved_dynamic_data_offset; dynamic->data_offset = saved_dynamic_data_offset;
put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr);
put_dt(dynamic, DT_STRTAB, dynstr->sh_addr); put_dt(dynamic, DT_STRTAB, dynstr->sh_addr);