aboutsummaryrefslogtreecommitdiff
path: root/tccelf.c
diff options
context:
space:
mode:
authorShinichiro Hamaji <shinichiro.hamaji _at_ gmail.com>2009-04-13 00:27:04 +0900
committergrischka <grischka>2009-04-18 15:08:01 +0200
commit830b7533c99f86203c4fbaf94897679678c3bad0 (patch)
treeed583dda98119b1248b857bdd20e22db457de0d5 /tccelf.c
parent6c10429aa5e7c65e725ed1989ddb856bbf7283aa (diff)
downloadtinycc-830b7533c99f86203c4fbaf94897679678c3bad0.tar.gz
tinycc-830b7533c99f86203c4fbaf94897679678c3bad0.tar.bz2
Generate PIC code so that we can create shared objects properly.
- Add got_table in TCCState. This approach is naive and the distance between executable code and GOT can be longer than 32bit. - Handle R_X86_64_GOTPCREL properly. We use got_table for TCC_OUTPUT_MEMORY case for now. - Fix load() and store() so that they access global variables via GOT.
Diffstat (limited to 'tccelf.c')
-rw-r--r--tccelf.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/tccelf.c b/tccelf.c
index 093f18d..56ee75a 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -502,6 +502,25 @@ static unsigned long add_jmp_table(TCCState *s1, unsigned long val)
*(unsigned long *)(p + 6) = val;
return (unsigned long)p;
}
+
+#define GOT_TABLE_ENTRY_MAX_NUM 4096
+static unsigned long add_got_table(TCCState *s1, unsigned long val)
+{
+ unsigned long *p;
+ if (!s1->got_table) {
+ int size = sizeof(void *) * GOT_TABLE_ENTRY_MAX_NUM;
+ s1->got_table_num = 0;
+ s1->got_table = (char *)tcc_malloc(size);
+ }
+ if (s1->got_table_num == GOT_TABLE_ENTRY_MAX_NUM) {
+ error("relocating >%d symbols are not supported",
+ GOT_TABLE_ENTRY_MAX_NUM);
+ }
+ p = s1->got_table + s1->got_table_num;
+ s1->got_table_num++;
+ *p = val;
+ return (unsigned long)p;
+}
#endif
/* relocate a given section (CPU dependent) */
@@ -727,11 +746,13 @@ static void relocate_section(TCCState *s1, Section *s)
*(int *)ptr = val;
break;
case R_X86_64_GOTPCREL:
- *(int *)ptr += s1->got->sh_addr - addr;
- /* XXX: is this OK? */
- if (s1->output_type == TCC_OUTPUT_DLL) {
- *(int *)ptr += s1->got_offsets[sym_index] - 4;
+ if (s1->output_type == TCC_OUTPUT_MEMORY) {
+ val = add_got_table(s1, val - rel->r_addend) + rel->r_addend;
+ *(int *)ptr += val - addr;
+ break;
}
+ *(int *)ptr += (s1->got->sh_addr - addr +
+ s1->got_offsets[sym_index] - 4);
break;
case R_X86_64_GOTTPOFF:
*(int *)ptr += val - s1->got->sh_addr;