Revert "Generate PLT thumb stub only when necessary"

Revert commit 891dfcdf3f since it assumes
*all* architectures supported by tcc have GOT offsets aligned on 2. A
rework of this commit is being done since without it all PLT entries
grow by 4 bytes.
master
Thomas Preud'homme 2012-11-12 23:14:21 +01:00
parent 3c986eeae3
commit 1af3bca4ea
2 changed files with 26 additions and 61 deletions

11
tcc.h
View File

@ -33,7 +33,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
@ -525,15 +524,11 @@ struct TCCState {
Section **priv_sections;
int nb_priv_sections; /* number of private sections */
/* got & plt handling */
/* got handling */
Section *got;
Section *plt;
struct {
unsigned long plt_thumb_stub:1;
/* mult by 2 (or left shift by 1) before use */
unsigned long got_offset:(sizeof(long)*CHAR_BIT-1);
} *sym_infos;
int nb_sym_infos;
unsigned long *got_offsets;
int nb_got_offsets;
/* give the correspondance from symtab indexes to dynsym indexes */
int *symtab_to_dynsym;

View File

@ -581,7 +581,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
break;
case R_386_GOT32:
/* we load the got offset */
*(int *)ptr += s1->sym_infos[sym_index].got_offset << 1;
*(int *)ptr += s1->got_offsets[sym_index];
break;
case R_386_16:
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {
@ -760,7 +760,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
break;
case R_ARM_GOT_BREL:
/* we load the got offset */
*(int *)ptr += s1->sym_infos[sym_index].got_offset << 1;
*(int *)ptr += s1->got_offsets[sym_index];
break;
case R_ARM_COPY:
break;
@ -866,14 +866,14 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
}
#endif
*(int *)ptr += (s1->got->sh_addr - addr +
(s1->sym_infos[sym_index].got_offset << 1) - 4);
s1->got_offsets[sym_index] - 4);
break;
case R_X86_64_GOTTPOFF:
*(int *)ptr += val - s1->got->sh_addr;
break;
case R_X86_64_GOT32:
/* we load the got offset */
*(int *)ptr += s1->sym_infos[sym_index].got_offset << 1;
*(int *)ptr += s1->got_offsets[sym_index];
break;
#else
#error unsupported processor
@ -943,36 +943,23 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr)
return count;
}
static void put_sym_info(TCCState *s1, int index)
static void put_got_offset(TCCState *s1, int index, unsigned long val)
{
int n;
typeof(s1->sym_infos) tab;
unsigned long *tab;
if (index >= s1->nb_sym_infos) {
if (index >= s1->nb_got_offsets) {
/* find immediately bigger power of 2 and reallocate array */
n = 1;
while (index >= n)
n *= 2;
tab = tcc_realloc(s1->sym_infos, n * sizeof(unsigned long));
s1->sym_infos = tab;
memset(s1->sym_infos + s1->nb_sym_infos, 0,
(n - s1->nb_sym_infos) * sizeof(unsigned long));
s1->nb_sym_infos = n;
tab = tcc_realloc(s1->got_offsets, n * sizeof(unsigned long));
s1->got_offsets = tab;
memset(s1->got_offsets + s1->nb_got_offsets, 0,
(n - s1->nb_got_offsets) * sizeof(unsigned long));
s1->nb_got_offsets = n;
}
}
#ifdef TCC_TARGET_ARM
static void put_plt_thumb_stub(TCCState *s1, int index, unsigned char bit)
{
put_sym_info(s1, index);
s1->sym_infos[index].plt_thumb_stub = bit;
}
#endif
static void put_got_offset(TCCState *s1, int index, unsigned long val)
{
put_sym_info(s1, index);
s1->sym_infos[index].got_offset = val >> 1;
s1->got_offsets[index] = val;
}
/* XXX: suppress that */
@ -1036,8 +1023,8 @@ static void put_got_entry(TCCState *s1,
build_got(s1);
/* if a got entry already exists for that symbol, no need to add one */
if (sym_index < s1->nb_sym_infos &&
s1->sym_infos[sym_index].got_offset << 1)
if (sym_index < s1->nb_got_offsets &&
s1->got_offsets[sym_index] != 0)
return;
put_got_offset(s1, sym_index, s1->got->data_offset);
@ -1117,13 +1104,10 @@ static void put_got_entry(TCCState *s1,
put32(p + 12, 0xe5bef008);
}
if (s1->sym_infos[sym_index].plt_thumb_stub) {
p = section_ptr_add(plt, 20);
put32(p , 0x4778); // bx pc
put32(p+2, 0x46c0); // nop
p += 4;
} else
p = section_ptr_add(plt, 16);
p = section_ptr_add(plt, 20);
put32(p , 0x4778); // bx pc
put32(p+2, 0x46c0); // nop
p += 4;
put32(p , 0xe59fc004); // ldr ip, [pc, #4] // offset in GOT
put32(p+4, 0xe08fc00c); // add ip, pc, ip // absolute address or offset
put32(p+8, 0xe59cf000); // ldr pc, [ip] // load absolute address or load offset
@ -1510,9 +1494,9 @@ ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
unsigned long offset;
if (sym_index >= s1->nb_sym_infos)
if (sym_index >= s1->nb_got_offsets)
return;
offset = s1->sym_infos[sym_index].got_offset << 1;
offset = s1->got_offsets[sym_index];
section_reserve(s1->got, offset + PTR_SIZE);
#ifdef TCC_TARGET_X86_64
/* only works for x86-64 */
@ -2086,8 +2070,7 @@ static int elf_output_file(TCCState *s1, const char *filename)
x=s1->got->sh_addr - s1->plt->sh_addr - 12;
p += 16;
while (p < p_end) {
if (get32(p) == 0x46c04778) /* PLT Thumb stub present */
p += 4;
p += 4;
put32(p + 12, x + get32(p + 12) + s1->plt->data - p);
p += 16;
}
@ -2321,7 +2304,7 @@ static int elf_output_file(TCCState *s1, const char *filename)
tcc_free(s1->symtab_to_dynsym);
tcc_free(section_order);
tcc_free(phdr);
tcc_free(s1->sym_infos);
tcc_free(s1->got_offsets);
return ret;
}
@ -2616,19 +2599,6 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
rel->r_info = ELFW(R_INFO)(sym_index, type);
/* offset the relocation offset */
rel->r_offset += offseti;
#ifdef TCC_TARGET_ARM
/* Jumps and branches from a Thumb code to a PLT entry need
special handling since PLT entries are ARM code.
Unconditional bl instructions referencing PLT entries are
handled by converting these instructions into blx
instructions. Other case of instructions referencing a PLT
entry require to add a Thumb stub before the PLT entry to
switch to ARM mode. We set bit 0 of the got offset of a
symbol to indicate such a case. */
if (type == R_ARM_THM_JUMP24) {
put_plt_thumb_stub(s1, sym_index, 1);
}
#endif
}
break;
default: