added symbol + relocation handling
This commit is contained in:
parent
46803f05e0
commit
d2115bfb27
2 changed files with 56 additions and 45 deletions
48
i386-gen.c
48
i386-gen.c
|
@ -132,7 +132,7 @@ void gsym(int t)
|
||||||
#define psym oad
|
#define psym oad
|
||||||
|
|
||||||
/* instruction + 4 bytes data. Return the address of the data */
|
/* instruction + 4 bytes data. Return the address of the data */
|
||||||
int oad(int c, int s)
|
static int oad(int c, int s)
|
||||||
{
|
{
|
||||||
int ind1;
|
int ind1;
|
||||||
|
|
||||||
|
@ -147,26 +147,22 @@ int oad(int c, int s)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* output constant with relocation if 'r & VT_SYM' is true */
|
/* output constant with relocation if 'r & VT_SYM' is true */
|
||||||
void gen_addr32(int r, int c)
|
static void gen_addr32(int r, Sym *sym, int c)
|
||||||
{
|
{
|
||||||
if (!(r & VT_SYM)) {
|
if (r & VT_SYM)
|
||||||
gen_le32(c);
|
greloc(cur_text_section, sym, ind, R_386_32);
|
||||||
} else {
|
gen_le32(c);
|
||||||
greloc(cur_text_section,
|
|
||||||
(Sym *)c, ind, R_386_32);
|
|
||||||
gen_le32(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* generate a modrm reference. 'op_reg' contains the addtionnal 3
|
/* generate a modrm reference. 'op_reg' contains the addtionnal 3
|
||||||
opcode bits */
|
opcode bits */
|
||||||
void gen_modrm(int op_reg, int r, int c)
|
static void gen_modrm(int op_reg, int r, Sym *sym, int c)
|
||||||
{
|
{
|
||||||
op_reg = op_reg << 3;
|
op_reg = op_reg << 3;
|
||||||
if ((r & VT_VALMASK) == VT_CONST) {
|
if ((r & VT_VALMASK) == VT_CONST) {
|
||||||
/* constant memory reference */
|
/* constant memory reference */
|
||||||
o(0x05 | op_reg);
|
o(0x05 | op_reg);
|
||||||
gen_addr32(r, c);
|
gen_addr32(r, sym, c);
|
||||||
} else if ((r & VT_VALMASK) == VT_LOCAL) {
|
} else if ((r & VT_VALMASK) == VT_LOCAL) {
|
||||||
/* currently, we use only ebp as base */
|
/* currently, we use only ebp as base */
|
||||||
if (c == (char)c) {
|
if (c == (char)c) {
|
||||||
|
@ -221,14 +217,14 @@ void load(int r, SValue *sv)
|
||||||
} else {
|
} else {
|
||||||
o(0x8b); /* movl */
|
o(0x8b); /* movl */
|
||||||
}
|
}
|
||||||
gen_modrm(r, fr, fc);
|
gen_modrm(r, fr, sv->sym, fc);
|
||||||
} else {
|
} else {
|
||||||
if (v == VT_CONST) {
|
if (v == VT_CONST) {
|
||||||
o(0xb8 + r); /* mov $xx, r */
|
o(0xb8 + r); /* mov $xx, r */
|
||||||
gen_addr32(fr, fc);
|
gen_addr32(fr, sv->sym, fc);
|
||||||
} else if (v == VT_LOCAL) {
|
} else if (v == VT_LOCAL) {
|
||||||
o(0x8d); /* lea xxx(%ebp), r */
|
o(0x8d); /* lea xxx(%ebp), r */
|
||||||
gen_modrm(r, VT_LOCAL, fc);
|
gen_modrm(r, VT_LOCAL, sv->sym, fc);
|
||||||
} else if (v == VT_CMP) {
|
} else if (v == VT_CMP) {
|
||||||
oad(0xb8 + r, 0); /* mov $0, r */
|
oad(0xb8 + r, 0); /* mov $0, r */
|
||||||
o(0x0f); /* setxx %br */
|
o(0x0f); /* setxx %br */
|
||||||
|
@ -278,7 +274,7 @@ void store(int r, SValue *v)
|
||||||
if (fr == VT_CONST ||
|
if (fr == VT_CONST ||
|
||||||
fr == VT_LOCAL ||
|
fr == VT_LOCAL ||
|
||||||
(v->r & VT_LVAL)) {
|
(v->r & VT_LVAL)) {
|
||||||
gen_modrm(r, v->r, fc);
|
gen_modrm(r, v->r, v->sym, fc);
|
||||||
} else if (fr != r) {
|
} else if (fr != r) {
|
||||||
o(0xc0 + fr + r * 8); /* mov r, fr */
|
o(0xc0 + fr + r * 8); /* mov r, fr */
|
||||||
}
|
}
|
||||||
|
@ -362,9 +358,9 @@ void gfunc_call(GFuncContext *c)
|
||||||
/* constant case */
|
/* constant case */
|
||||||
if (vtop->r & VT_SYM) {
|
if (vtop->r & VT_SYM) {
|
||||||
/* relocation case */
|
/* relocation case */
|
||||||
greloc(cur_text_section, vtop->c.sym,
|
greloc(cur_text_section, vtop->sym,
|
||||||
ind + 1, R_386_PC32);
|
ind + 1, R_386_PC32);
|
||||||
oad(0xe8, -4);
|
oad(0xe8, vtop->c.ul - 4);
|
||||||
} else {
|
} else {
|
||||||
oad(0xe8, vtop->c.ul - ind - 5);
|
oad(0xe8, vtop->c.ul - ind - 5);
|
||||||
}
|
}
|
||||||
|
@ -443,7 +439,7 @@ void gfunc_epilog(void)
|
||||||
greloc(cur_text_section, sym_data,
|
greloc(cur_text_section, sym_data,
|
||||||
ind + 1, R_386_32);
|
ind + 1, R_386_32);
|
||||||
oad(0xb8, 0); /* mov %eax, xxx */
|
oad(0xb8, 0); /* mov %eax, xxx */
|
||||||
sym = external_sym(TOK___bound_local_new, func_old_type, 0);
|
sym = external_global_sym(TOK___bound_local_new, func_old_type, 0);
|
||||||
greloc(cur_text_section, sym,
|
greloc(cur_text_section, sym,
|
||||||
ind + 1, R_386_PC32);
|
ind + 1, R_386_PC32);
|
||||||
oad(0xe8, -4);
|
oad(0xe8, -4);
|
||||||
|
@ -453,7 +449,7 @@ void gfunc_epilog(void)
|
||||||
greloc(cur_text_section, sym_data,
|
greloc(cur_text_section, sym_data,
|
||||||
ind + 1, R_386_32);
|
ind + 1, R_386_32);
|
||||||
oad(0xb8, 0); /* mov %eax, xxx */
|
oad(0xb8, 0); /* mov %eax, xxx */
|
||||||
sym = external_sym(TOK___bound_local_delete, func_old_type, 0);
|
sym = external_global_sym(TOK___bound_local_delete, func_old_type, 0);
|
||||||
greloc(cur_text_section, sym,
|
greloc(cur_text_section, sym,
|
||||||
ind + 1, R_386_PC32);
|
ind + 1, R_386_PC32);
|
||||||
oad(0xe8, -4);
|
oad(0xe8, -4);
|
||||||
|
@ -766,7 +762,7 @@ void gen_opf(int op)
|
||||||
o(0xdc);
|
o(0xdc);
|
||||||
else
|
else
|
||||||
o(0xd8);
|
o(0xd8);
|
||||||
gen_modrm(a, r, fc);
|
gen_modrm(a, r, vtop->sym, fc);
|
||||||
}
|
}
|
||||||
vtop--;
|
vtop--;
|
||||||
}
|
}
|
||||||
|
@ -816,8 +812,8 @@ void gen_cvt_ftoi(int t)
|
||||||
size = 4;
|
size = 4;
|
||||||
|
|
||||||
o(0x2dd9); /* ldcw xxx */
|
o(0x2dd9); /* ldcw xxx */
|
||||||
sym = external_sym(TOK___tcc_int_fpu_control,
|
sym = external_global_sym(TOK___tcc_int_fpu_control,
|
||||||
VT_SHORT | VT_UNSIGNED, VT_LVAL);
|
VT_SHORT | VT_UNSIGNED, VT_LVAL);
|
||||||
greloc(cur_text_section, sym,
|
greloc(cur_text_section, sym,
|
||||||
ind, R_386_32);
|
ind, R_386_32);
|
||||||
gen_le32(0);
|
gen_le32(0);
|
||||||
|
@ -829,8 +825,8 @@ void gen_cvt_ftoi(int t)
|
||||||
o(0x3cdf); /* fistpll */
|
o(0x3cdf); /* fistpll */
|
||||||
o(0x24);
|
o(0x24);
|
||||||
o(0x2dd9); /* ldcw xxx */
|
o(0x2dd9); /* ldcw xxx */
|
||||||
sym = external_sym(TOK___tcc_fpu_control,
|
sym = external_global_sym(TOK___tcc_fpu_control,
|
||||||
VT_SHORT | VT_UNSIGNED, VT_LVAL);
|
VT_SHORT | VT_UNSIGNED, VT_LVAL);
|
||||||
greloc(cur_text_section, sym,
|
greloc(cur_text_section, sym,
|
||||||
ind, R_386_32);
|
ind, R_386_32);
|
||||||
gen_le32(0);
|
gen_le32(0);
|
||||||
|
@ -871,7 +867,7 @@ void gen_bounded_ptr_add(void)
|
||||||
vtop -= 2;
|
vtop -= 2;
|
||||||
save_regs(0);
|
save_regs(0);
|
||||||
/* do a fast function call */
|
/* do a fast function call */
|
||||||
sym = external_sym(TOK___bound_ptr_add, func_old_type, 0);
|
sym = external_global_sym(TOK___bound_ptr_add, func_old_type, 0);
|
||||||
greloc(cur_text_section, sym,
|
greloc(cur_text_section, sym,
|
||||||
ind + 1, R_386_PC32);
|
ind + 1, R_386_PC32);
|
||||||
oad(0xe8, -4);
|
oad(0xe8, -4);
|
||||||
|
@ -917,7 +913,7 @@ void gen_bounded_ptr_deref(void)
|
||||||
/* patch relocation */
|
/* patch relocation */
|
||||||
/* XXX: find a better solution ? */
|
/* XXX: find a better solution ? */
|
||||||
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul);
|
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul);
|
||||||
sym = external_sym(func, func_old_type, 0);
|
sym = external_global_sym(func, func_old_type, 0);
|
||||||
if (!sym->c)
|
if (!sym->c)
|
||||||
put_extern_sym(sym, NULL, 0, 0);
|
put_extern_sym(sym, NULL, 0, 0);
|
||||||
rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
|
rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
|
||||||
|
|
53
tcc.c
53
tcc.c
|
@ -100,7 +100,6 @@ typedef union CValue {
|
||||||
long long ll;
|
long long ll;
|
||||||
unsigned long long ull;
|
unsigned long long ull;
|
||||||
struct CString *cstr;
|
struct CString *cstr;
|
||||||
struct Sym *sym;
|
|
||||||
void *ptr;
|
void *ptr;
|
||||||
int tab[1];
|
int tab[1];
|
||||||
} CValue;
|
} CValue;
|
||||||
|
@ -112,6 +111,7 @@ typedef struct SValue {
|
||||||
unsigned short r2; /* second register, used for 'long long'
|
unsigned short r2; /* second register, used for 'long long'
|
||||||
type. If not used, set to VT_CONST */
|
type. If not used, set to VT_CONST */
|
||||||
CValue c; /* constant, if VT_CONST */
|
CValue c; /* constant, if VT_CONST */
|
||||||
|
struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */
|
||||||
} SValue;
|
} SValue;
|
||||||
|
|
||||||
/* symbol management */
|
/* symbol management */
|
||||||
|
@ -548,7 +548,7 @@ static char *pstrcat(char *buf, int buf_size, const char *s);
|
||||||
void sum(int l);
|
void sum(int l);
|
||||||
void next(void);
|
void next(void);
|
||||||
void next_nomacro(void);
|
void next_nomacro(void);
|
||||||
int expr_const(void);
|
static int expr_const(void);
|
||||||
void expr_eq(void);
|
void expr_eq(void);
|
||||||
void gexpr(void);
|
void gexpr(void);
|
||||||
void decl(int l);
|
void decl(int l);
|
||||||
|
@ -2895,8 +2895,9 @@ static void vpush_ref(int t, Section *sec, unsigned long offset, unsigned long s
|
||||||
{
|
{
|
||||||
CValue cval;
|
CValue cval;
|
||||||
|
|
||||||
cval.sym = get_sym_ref(t, sec, offset, size);
|
cval.ul = 0;
|
||||||
vsetc(t, VT_CONST | VT_SYM, &cval);
|
vsetc(t, VT_CONST | VT_SYM, &cval);
|
||||||
|
vtop->sym = get_sym_ref(t, sec, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* define a new external reference to a symbol 'v' of type 'u' */
|
/* define a new external reference to a symbol 'v' of type 'u' */
|
||||||
|
@ -2934,8 +2935,9 @@ static void vpush_global_sym(int t, int v)
|
||||||
CValue cval;
|
CValue cval;
|
||||||
|
|
||||||
sym = external_global_sym(v, t, 0);
|
sym = external_global_sym(v, t, 0);
|
||||||
cval.sym = sym;
|
cval.ul = 0;
|
||||||
vsetc(t, VT_CONST | VT_SYM, &cval);
|
vsetc(t, VT_CONST | VT_SYM, &cval);
|
||||||
|
vtop->sym = sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vset(int t, int r, int v)
|
void vset(int t, int r, int v)
|
||||||
|
@ -3160,7 +3162,8 @@ int gv(int rc)
|
||||||
ptr[i] = vtop->c.tab[i];
|
ptr[i] = vtop->c.tab[i];
|
||||||
sym = get_sym_ref(vtop->t, data_section, offset, size << 2);
|
sym = get_sym_ref(vtop->t, data_section, offset, size << 2);
|
||||||
vtop->r |= VT_LVAL | VT_SYM;
|
vtop->r |= VT_LVAL | VT_SYM;
|
||||||
vtop->c.sym = sym;
|
vtop->sym = sym;
|
||||||
|
vtop->c.ul = 0;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
if (vtop->r & VT_MUSTBOUND)
|
if (vtop->r & VT_MUSTBOUND)
|
||||||
|
@ -3675,6 +3678,14 @@ void gen_opic(int op)
|
||||||
op = TOK_SHR;
|
op = TOK_SHR;
|
||||||
}
|
}
|
||||||
goto general_case;
|
goto general_case;
|
||||||
|
} else if (c2 && (op == '+' || op == '-') &&
|
||||||
|
(vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) ==
|
||||||
|
(VT_CONST | VT_SYM)) {
|
||||||
|
/* symbol + constant case */
|
||||||
|
if (op == '-')
|
||||||
|
fc = -fc;
|
||||||
|
vtop--;
|
||||||
|
vtop->c.i += fc;
|
||||||
} else {
|
} else {
|
||||||
general_case:
|
general_case:
|
||||||
/* call low level op generator */
|
/* call low level op generator */
|
||||||
|
@ -5189,8 +5200,10 @@ void unary(void)
|
||||||
}
|
}
|
||||||
vset(s->t, s->r, s->c);
|
vset(s->t, s->r, s->c);
|
||||||
/* if forward reference, we must point to s */
|
/* if forward reference, we must point to s */
|
||||||
if (vtop->r & VT_SYM)
|
if (vtop->r & VT_SYM) {
|
||||||
vtop->c.sym = s;
|
vtop->sym = s;
|
||||||
|
vtop->c.ul = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5273,7 +5286,7 @@ void unary(void)
|
||||||
tok_str_new(&str);
|
tok_str_new(&str);
|
||||||
parlevel = 0;
|
parlevel = 0;
|
||||||
while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
|
while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
|
||||||
tok != -1) {
|
tok != TOK_EOF) {
|
||||||
if (tok == '(')
|
if (tok == '(')
|
||||||
parlevel++;
|
parlevel++;
|
||||||
else if (tok == ')')
|
else if (tok == ')')
|
||||||
|
@ -5509,23 +5522,23 @@ void gexpr(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse a constant expression and return value in vtop */
|
/* parse a constant expression and return value in vtop. */
|
||||||
void expr_const1(void)
|
static void expr_const1(void)
|
||||||
{
|
{
|
||||||
int a;
|
int a;
|
||||||
a = const_wanted;
|
a = const_wanted;
|
||||||
const_wanted = 1;
|
const_wanted = 1;
|
||||||
expr_eq();
|
expr_eq();
|
||||||
if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST)
|
|
||||||
expect("constant");
|
|
||||||
const_wanted = a;
|
const_wanted = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse an integer constant and return its value */
|
/* parse an integer constant and return its value. */
|
||||||
int expr_const(void)
|
static int expr_const(void)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
expr_const1();
|
expr_const1();
|
||||||
|
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
|
||||||
|
expect("constant expression");
|
||||||
c = vtop->c.i;
|
c = vtop->c.i;
|
||||||
vpop();
|
vpop();
|
||||||
return c;
|
return c;
|
||||||
|
@ -5899,6 +5912,9 @@ static void init_putv(int t, Section *sec, unsigned long c,
|
||||||
global_expr = 1;
|
global_expr = 1;
|
||||||
expr_const1();
|
expr_const1();
|
||||||
global_expr = saved_global_expr;
|
global_expr = saved_global_expr;
|
||||||
|
/* NOTE: symbols are accepted */
|
||||||
|
if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST)
|
||||||
|
error("initializer element is not constant");
|
||||||
break;
|
break;
|
||||||
case EXPR_ANY:
|
case EXPR_ANY:
|
||||||
expr_eq();
|
expr_eq();
|
||||||
|
@ -5936,11 +5952,9 @@ static void init_putv(int t, Section *sec, unsigned long c,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (vtop->r & VT_SYM) {
|
if (vtop->r & VT_SYM) {
|
||||||
greloc(sec, vtop->c.sym, c, R_DATA_32);
|
greloc(sec, vtop->sym, c, R_DATA_32);
|
||||||
*(int *)ptr = 0;
|
|
||||||
} else {
|
|
||||||
*(int *)ptr = vtop->c.i;
|
|
||||||
}
|
}
|
||||||
|
*(int *)ptr = vtop->c.i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
vtop--;
|
vtop--;
|
||||||
|
@ -6284,8 +6298,9 @@ static void decl_initializer_alloc(int t, AttributeDef *ad, int r,
|
||||||
|
|
||||||
/* push global reference */
|
/* push global reference */
|
||||||
sym = get_sym_ref(t, sec, addr, size);
|
sym = get_sym_ref(t, sec, addr, size);
|
||||||
cval.sym = sym;
|
cval.ul = 0;
|
||||||
vsetc(t, VT_CONST | VT_SYM, &cval);
|
vsetc(t, VT_CONST | VT_SYM, &cval);
|
||||||
|
vtop->sym = sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handles bounds now because the symbol must be defined
|
/* handles bounds now because the symbol must be defined
|
||||||
|
|
Loading…
Reference in a new issue