aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libtcc.c10
-rw-r--r--tcc.h2
-rw-r--r--tccelf.c15
-rw-r--r--tccgen.c32
4 files changed, 46 insertions, 13 deletions
diff --git a/libtcc.c b/libtcc.c
index 711cdd2..01497b2 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -536,7 +536,8 @@ ST_FUNC void put_extern_sym(Sym *sym, Section *section,
}
/* add a new relocation entry to symbol 'sym' in section 's' */
-ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type)
+ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type,
+ unsigned long addend)
{
int c = 0;
if (sym) {
@@ -545,7 +546,12 @@ ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type)
c = sym->c;
}
/* now we can add ELF relocation info */
- put_elf_reloc(symtab_section, s, offset, type, c);
+ put_elf_reloca(symtab_section, s, offset, type, c, addend);
+}
+
+ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type)
+{
+ greloca(s, sym, offset, type, 0);
}
/********************************************************/
diff --git a/tcc.h b/tcc.h
index 3f7d43b..aaf5be0 100644
--- a/tcc.h
+++ b/tcc.h
@@ -1074,6 +1074,7 @@ ST_FUNC Section *find_section(TCCState *s1, const char *name);
ST_FUNC void put_extern_sym2(Sym *sym, Section *section, addr_t value, unsigned long size, int can_add_underscore);
ST_FUNC void put_extern_sym(Sym *sym, Section *section, addr_t value, unsigned long size);
ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type);
+ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, unsigned long addend);
ST_INLN void sym_free(Sym *sym);
ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c);
@@ -1261,6 +1262,7 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info,
ST_FUNC int add_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int sh_num, const char *name);
ST_FUNC int find_elf_sym(Section *s, const char *name);
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol);
+ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, int type, int symbol, unsigned long addend);
ST_FUNC void put_stabs(const char *str, int type, int other, int desc, unsigned long value);
ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index);
diff --git a/tccelf.c b/tccelf.c
index 02caa68..dc0a144 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -269,8 +269,8 @@ ST_FUNC int add_elf_sym(Section *s, addr_t value, unsigned long size,
}
/* put relocation */
-ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
- int type, int symbol)
+ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
+ int type, int symbol, unsigned long addend)
{
char buf[256];
Section *sr;
@@ -292,10 +292,19 @@ ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
rel->r_offset = offset;
rel->r_info = ELFW(R_INFO)(symbol, type);
#ifdef TCC_TARGET_X86_64
- rel->r_addend = 0;
+ rel->r_addend = addend;
+#else
+ if (addend)
+ tcc_error("non-zero addend on REL architecture");
#endif
}
+ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
+ int type, int symbol)
+{
+ put_elf_reloca(symtab, s, offset, type, symbol, 0);
+}
+
/* put stab debug information */
ST_FUNC void put_stabs(const char *str, int type, int other, int desc,
diff --git a/tccgen.c b/tccgen.c
index 510051a..ae07563 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -5201,19 +5201,35 @@ static void init_putv(CType *type, Section *sec, unsigned long c,
case VT_LLONG:
*(long long *)ptr |= (vtop->c.ll & bit_mask) << bit_pos;
break;
- case VT_PTR:
- if (vtop->r & VT_SYM) {
+ case VT_PTR: {
+ addr_t val = (vtop->c.ptr_offset & bit_mask) << bit_pos;
+#ifdef TCC_TARGET_X86_64
+ if (vtop->r & VT_SYM)
+ greloca(sec, vtop->sym, c, R_DATA_PTR, val);
+ else
+ *(addr_t *)ptr |= val;
+#else
+ if (vtop->r & VT_SYM)
greloc(sec, vtop->sym, c, R_DATA_PTR);
- }
- *(addr_t *)ptr |= (vtop->c.ptr_offset & bit_mask) << bit_pos;
+ *(addr_t *)ptr |= val;
+#endif
break;
- default:
- if (vtop->r & VT_SYM) {
+ }
+ default: {
+ int val = (vtop->c.i & bit_mask) << bit_pos;
+#ifdef TCC_TARGET_X86_64
+ if (vtop->r & VT_SYM)
+ greloca(sec, vtop->sym, c, R_DATA_PTR, val);
+ else
+ *(int *)ptr |= val;
+#else
+ if (vtop->r & VT_SYM)
greloc(sec, vtop->sym, c, R_DATA_PTR);
- }
- *(int *)ptr |= (vtop->c.i & bit_mask) << bit_pos;
+ *(int *)ptr |= val;
+#endif
break;
}
+ }
vtop--;
} else {
vset(&dtype, VT_LOCAL|VT_LVAL, c);