Accept more asm expressions
In particular subtracting a defined symbol from current section makes the value PC relative, and .org accepts symbolic expressions as well, if the symbol is from the current section.
This commit is contained in:
parent
c82e52d55b
commit
8e4da42384
4 changed files with 60 additions and 23 deletions
14
i386-asm.c
14
i386-asm.c
|
@ -356,8 +356,7 @@ static void parse_operand(TCCState *s1, Operand *op)
|
||||||
next();
|
next();
|
||||||
asm_expr(s1, &e);
|
asm_expr(s1, &e);
|
||||||
op->type = OP_IM32;
|
op->type = OP_IM32;
|
||||||
op->e.v = e.v;
|
op->e = e;
|
||||||
op->e.sym = e.sym;
|
|
||||||
if (!op->e.sym) {
|
if (!op->e.sym) {
|
||||||
if (op->e.v == (uint8_t)op->e.v)
|
if (op->e.v == (uint8_t)op->e.v)
|
||||||
op->type |= OP_IM8;
|
op->type |= OP_IM8;
|
||||||
|
@ -378,8 +377,7 @@ static void parse_operand(TCCState *s1, Operand *op)
|
||||||
op->shift = 0;
|
op->shift = 0;
|
||||||
if (tok != '(') {
|
if (tok != '(') {
|
||||||
asm_expr(s1, &e);
|
asm_expr(s1, &e);
|
||||||
op->e.v = e.v;
|
op->e = e;
|
||||||
op->e.sym = e.sym;
|
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
if (tok == '%') {
|
if (tok == '%') {
|
||||||
|
@ -395,6 +393,7 @@ static void parse_operand(TCCState *s1, Operand *op)
|
||||||
op->e.v = e.v;
|
op->e.v = e.v;
|
||||||
op->e.sym = e.sym;
|
op->e.sym = e.sym;
|
||||||
}
|
}
|
||||||
|
op->e.pcrel = 0;
|
||||||
}
|
}
|
||||||
if (tok == '(') {
|
if (tok == '(') {
|
||||||
int type = 0;
|
int type = 0;
|
||||||
|
@ -425,7 +424,12 @@ static void parse_operand(TCCState *s1, Operand *op)
|
||||||
/* XXX: unify with C code output ? */
|
/* XXX: unify with C code output ? */
|
||||||
ST_FUNC void gen_expr32(ExprValue *pe)
|
ST_FUNC void gen_expr32(ExprValue *pe)
|
||||||
{
|
{
|
||||||
gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
|
if (pe->pcrel)
|
||||||
|
/* If PC-relative, always set VT_SYM, even without symbol,
|
||||||
|
so as to force a relocation to be emitted. */
|
||||||
|
gen_addrpc32(VT_SYM, pe->sym, pe->v);
|
||||||
|
else
|
||||||
|
gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
|
|
1
tcc.h
1
tcc.h
|
@ -555,6 +555,7 @@ typedef struct CachedInclude {
|
||||||
typedef struct ExprValue {
|
typedef struct ExprValue {
|
||||||
uint64_t v;
|
uint64_t v;
|
||||||
Sym *sym;
|
Sym *sym;
|
||||||
|
int pcrel;
|
||||||
} ExprValue;
|
} ExprValue;
|
||||||
|
|
||||||
#define MAX_ASM_OPERANDS 30
|
#define MAX_ASM_OPERANDS 30
|
||||||
|
|
55
tccasm.c
55
tccasm.c
|
@ -67,11 +67,13 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||||
sym->type.t = VT_STATIC | VT_VOID;
|
sym->type.t = VT_STATIC | VT_VOID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pe->v = 0;
|
pe->v = 0;
|
||||||
pe->sym = sym;
|
pe->sym = sym;
|
||||||
|
pe->pcrel = 0;
|
||||||
} else if (*p == '\0') {
|
} else if (*p == '\0') {
|
||||||
pe->v = n;
|
pe->v = n;
|
||||||
pe->sym = NULL;
|
pe->sym = NULL;
|
||||||
|
pe->pcrel = 0;
|
||||||
} else {
|
} else {
|
||||||
tcc_error("invalid number syntax");
|
tcc_error("invalid number syntax");
|
||||||
}
|
}
|
||||||
|
@ -97,6 +99,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||||
case TOK_LCHAR:
|
case TOK_LCHAR:
|
||||||
pe->v = tokc.i;
|
pe->v = tokc.i;
|
||||||
pe->sym = NULL;
|
pe->sym = NULL;
|
||||||
|
pe->pcrel = 0;
|
||||||
next();
|
next();
|
||||||
break;
|
break;
|
||||||
case '(':
|
case '(':
|
||||||
|
@ -107,6 +110,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||||
case '.':
|
case '.':
|
||||||
pe->v = 0;
|
pe->v = 0;
|
||||||
pe->sym = &sym_dot;
|
pe->sym = &sym_dot;
|
||||||
|
pe->pcrel = 0;
|
||||||
sym_dot.type.t = VT_VOID | VT_STATIC;
|
sym_dot.type.t = VT_VOID | VT_STATIC;
|
||||||
sym_dot.r = cur_text_section->sh_num;
|
sym_dot.r = cur_text_section->sh_num;
|
||||||
sym_dot.jnext = ind;
|
sym_dot.jnext = ind;
|
||||||
|
@ -125,9 +129,11 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||||
/* if absolute symbol, no need to put a symbol value */
|
/* if absolute symbol, no need to put a symbol value */
|
||||||
pe->v = sym->jnext;
|
pe->v = sym->jnext;
|
||||||
pe->sym = NULL;
|
pe->sym = NULL;
|
||||||
|
pe->pcrel = 0;
|
||||||
} else {
|
} else {
|
||||||
pe->v = 0;
|
pe->v = 0;
|
||||||
pe->sym = sym;
|
pe->sym = sym;
|
||||||
|
pe->pcrel = 0;
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
|
@ -230,20 +236,21 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
|
||||||
pe->v -= e2.v;
|
pe->v -= e2.v;
|
||||||
/* NOTE: we are less powerful than gas in that case
|
/* NOTE: we are less powerful than gas in that case
|
||||||
because we store only one symbol in the expression */
|
because we store only one symbol in the expression */
|
||||||
if (!pe->sym && !e2.sym) {
|
if (!e2.sym) {
|
||||||
/* OK */
|
/* OK */
|
||||||
} else if (pe->sym && !e2.sym) {
|
} else if (pe->sym == e2.sym) {
|
||||||
/* OK */
|
/* OK */
|
||||||
} else if (pe->sym && e2.sym) {
|
pe->sym = NULL; /* same symbols can be subtracted to NULL */
|
||||||
if (pe->sym == e2.sym) {
|
} else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) {
|
||||||
/* OK */
|
/* we also accept defined symbols in the same section */
|
||||||
} else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) {
|
pe->v += pe->sym->jnext - e2.sym->jnext;
|
||||||
/* we also accept defined symbols in the same section */
|
pe->sym = NULL;
|
||||||
pe->v += pe->sym->jnext - e2.sym->jnext;
|
} else if (e2.sym->r == cur_text_section->sh_num) {
|
||||||
} else {
|
/* When subtracting a defined symbol in current section
|
||||||
goto cannot_relocate;
|
this actually makes the value PC-relative. */
|
||||||
}
|
pe->v -= e2.sym->jnext - ind - 4;
|
||||||
pe->sym = NULL; /* same symbols can be subtracted to NULL */
|
pe->pcrel = 1;
|
||||||
|
e2.sym = NULL;
|
||||||
} else {
|
} else {
|
||||||
cannot_relocate:
|
cannot_relocate:
|
||||||
tcc_error("invalid operation with label");
|
tcc_error("invalid operation with label");
|
||||||
|
@ -531,9 +538,15 @@ static void asm_parse_directive(TCCState *s1)
|
||||||
case TOK_ASMDIR_org:
|
case TOK_ASMDIR_org:
|
||||||
{
|
{
|
||||||
unsigned long n;
|
unsigned long n;
|
||||||
|
ExprValue e;
|
||||||
next();
|
next();
|
||||||
/* XXX: handle section symbols too */
|
asm_expr(s1, &e);
|
||||||
n = asm_int_expr(s1);
|
n = e.v;
|
||||||
|
if (e.sym) {
|
||||||
|
if (e.sym->r != cur_text_section->sh_num)
|
||||||
|
expect("constant or same-section symbol");
|
||||||
|
n += e.sym->jnext;
|
||||||
|
}
|
||||||
if (n < ind)
|
if (n < ind)
|
||||||
tcc_error("attempt to .org backwards");
|
tcc_error("attempt to .org backwards");
|
||||||
v = 0;
|
v = 0;
|
||||||
|
@ -703,6 +716,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||||
case TOK_ASMDIR_section:
|
case TOK_ASMDIR_section:
|
||||||
{
|
{
|
||||||
char sname[256];
|
char sname[256];
|
||||||
|
int old_nb_section = s1->nb_sections;
|
||||||
|
|
||||||
tok1 = tok;
|
tok1 = tok;
|
||||||
/* XXX: support more options */
|
/* XXX: support more options */
|
||||||
|
@ -733,6 +747,11 @@ static void asm_parse_directive(TCCState *s1)
|
||||||
use_section(s1, sname);
|
use_section(s1, sname);
|
||||||
else
|
else
|
||||||
push_section(s1, sname);
|
push_section(s1, sname);
|
||||||
|
/* If we just allocated a new section reset its alignment to
|
||||||
|
1. new_section normally acts for GCC compatibility and
|
||||||
|
sets alignment to PTR_SIZE. The assembler behaves different. */
|
||||||
|
if (old_nb_section != s1->nb_sections)
|
||||||
|
cur_text_section->sh_addralign = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TOK_ASMDIR_previous:
|
case TOK_ASMDIR_previous:
|
||||||
|
|
|
@ -727,6 +727,19 @@ nop
|
||||||
.popsection
|
.popsection
|
||||||
.popsection
|
.popsection
|
||||||
|
|
||||||
|
1: ud2
|
||||||
|
.pushsection __bug_table,"a"
|
||||||
|
.align 8
|
||||||
|
2: .long 1b - 2b
|
||||||
|
.long 0x600000 - 2b
|
||||||
|
.long 1b + 42
|
||||||
|
.long 43 + 1b
|
||||||
|
.long 2b + 144
|
||||||
|
.long 145 + 2b
|
||||||
|
.word 164, 0
|
||||||
|
.org 2b+32
|
||||||
|
.popsection
|
||||||
|
|
||||||
movd %esi, %mm1
|
movd %esi, %mm1
|
||||||
movd %edi, %xmm2
|
movd %edi, %xmm2
|
||||||
movd (%ebx), %mm3
|
movd (%ebx), %mm3
|
||||||
|
|
Loading…
Reference in a new issue