mirror of
https://github.com/frida/tinycc
synced 2024-12-25 14:36:49 +03:00
tccasm: Lookup C symbols from ASM blocks
It's now possible to use symbols defined in C code to be used from later inline asm blocks. See testcase.
This commit is contained in:
parent
c4edfb4e08
commit
9ae10cad1f
62
tccasm.c
62
tccasm.c
@ -35,6 +35,45 @@ ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
|
|||||||
static int tcc_assemble_internal(TCCState *s1, int do_preprocess);
|
static int tcc_assemble_internal(TCCState *s1, int do_preprocess);
|
||||||
static Sym sym_dot;
|
static Sym sym_dot;
|
||||||
|
|
||||||
|
/* Return a symbol we can use inside the assembler, having name NAME.
|
||||||
|
The assembler symbol table is different from the C symbol table
|
||||||
|
(and the Sym members are used differently). But we must be able
|
||||||
|
to look up file-global C symbols from inside the assembler, e.g.
|
||||||
|
for global asm blocks to be able to refer to defined C symbols.
|
||||||
|
|
||||||
|
This routine gives back either an existing asm-internal
|
||||||
|
symbol, or a new one. In the latter case the new asm-internal
|
||||||
|
symbol is initialized with info from the C symbol table. */
|
||||||
|
static Sym* get_asm_sym(int name)
|
||||||
|
{
|
||||||
|
Sym *sym = label_find(name);
|
||||||
|
if (!sym) {
|
||||||
|
Sym *csym = sym_find(name);
|
||||||
|
sym = label_push(&tcc_state->asm_labels, name, 0);
|
||||||
|
sym->type.t = VT_VOID | VT_EXTERN;
|
||||||
|
/* We might be called for an asm block from inside a C routine
|
||||||
|
and so might have local decls on the identifier stack. Search
|
||||||
|
for the first global one. */
|
||||||
|
while (csym && csym->scope)
|
||||||
|
csym = csym->prev_tok;
|
||||||
|
/* Now, if we have a defined global symbol copy over
|
||||||
|
section and offset. */
|
||||||
|
if (csym &&
|
||||||
|
((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) &&
|
||||||
|
csym->c) {
|
||||||
|
ElfW(Sym) *esym;
|
||||||
|
esym = &((ElfW(Sym) *)symtab_section->data)[csym->c];
|
||||||
|
sym->r = esym->st_shndx;
|
||||||
|
sym->jnext = esym->st_value;
|
||||||
|
/* XXX can't yet store st_size anywhere. */
|
||||||
|
sym->type.t &= ~VT_EXTERN;
|
||||||
|
/* Mark that this asm symbol doesn't need to be fed back. */
|
||||||
|
sym->type.t |= VT_IMPORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
|
||||||
/* We do not use the C expression parser to handle symbols. Maybe the
|
/* We do not use the C expression parser to handle symbols. Maybe the
|
||||||
C expression parser could be tweaked to do so. */
|
C expression parser could be tweaked to do so. */
|
||||||
|
|
||||||
@ -119,12 +158,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
|||||||
default:
|
default:
|
||||||
if (tok >= TOK_IDENT) {
|
if (tok >= TOK_IDENT) {
|
||||||
/* label case : if the label was not found, add one */
|
/* label case : if the label was not found, add one */
|
||||||
sym = label_find(tok);
|
sym = get_asm_sym(tok);
|
||||||
if (!sym) {
|
|
||||||
sym = label_push(&s1->asm_labels, tok, 0);
|
|
||||||
/* NOTE: by default, the symbol is global */
|
|
||||||
sym->type.t = VT_VOID | VT_EXTERN;
|
|
||||||
}
|
|
||||||
if (sym->r == SHN_ABS) {
|
if (sym->r == SHN_ABS) {
|
||||||
/* 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;
|
||||||
@ -359,7 +393,6 @@ static Sym* asm_new_label(TCCState *s1, int label, int is_local)
|
|||||||
involving other symbols). LABEL can be overwritten later still. */
|
involving other symbols). LABEL can be overwritten later still. */
|
||||||
static Sym* set_symbol(TCCState *s1, int label)
|
static Sym* set_symbol(TCCState *s1, int label)
|
||||||
{
|
{
|
||||||
Sym *sym;
|
|
||||||
long n;
|
long n;
|
||||||
ExprValue e;
|
ExprValue e;
|
||||||
next();
|
next();
|
||||||
@ -379,7 +412,7 @@ static void asm_free_labels(TCCState *st)
|
|||||||
s1 = s->prev;
|
s1 = s->prev;
|
||||||
/* define symbol value in object file */
|
/* define symbol value in object file */
|
||||||
s->type.t &= ~VT_EXTERN;
|
s->type.t &= ~VT_EXTERN;
|
||||||
if (s->r) {
|
if (s->r && !(s->type.t & VT_IMPORT)) {
|
||||||
if (s->r == SHN_ABS)
|
if (s->r == SHN_ABS)
|
||||||
sec = SECTION_ABS;
|
sec = SECTION_ABS;
|
||||||
else
|
else
|
||||||
@ -649,11 +682,7 @@ static void asm_parse_directive(TCCState *s1)
|
|||||||
Sym *sym;
|
Sym *sym;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
sym = label_find(tok);
|
sym = get_asm_sym(tok);
|
||||||
if (!sym) {
|
|
||||||
sym = label_push(&s1->asm_labels, tok, 0);
|
|
||||||
sym->type.t = VT_VOID | VT_EXTERN;
|
|
||||||
}
|
|
||||||
if (tok1 != TOK_ASMDIR_hidden)
|
if (tok1 != TOK_ASMDIR_hidden)
|
||||||
sym->type.t &= ~VT_STATIC;
|
sym->type.t &= ~VT_STATIC;
|
||||||
if (tok1 == TOK_ASMDIR_weak)
|
if (tok1 == TOK_ASMDIR_weak)
|
||||||
@ -772,12 +801,7 @@ static void asm_parse_directive(TCCState *s1)
|
|||||||
const char *newtype;
|
const char *newtype;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
sym = label_find(tok);
|
sym = get_asm_sym(tok);
|
||||||
if (!sym) {
|
|
||||||
sym = label_push(&s1->asm_labels, tok, 0);
|
|
||||||
sym->type.t = VT_VOID | VT_EXTERN;
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
next();
|
||||||
skip(',');
|
skip(',');
|
||||||
if (tok == TOK_STR) {
|
if (tok == TOK_STR) {
|
||||||
|
@ -2647,6 +2647,24 @@ void other_constraints_test(void)
|
|||||||
printf ("oc1: %d\n", ret == (unsigned long)&var);
|
printf ("oc1: %d\n", ret == (unsigned long)&var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Test global asm blocks playing with aliases. */
|
||||||
|
void base_func(void)
|
||||||
|
{
|
||||||
|
printf ("asmc: base\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void override_func1 (void);
|
||||||
|
extern void override_func2 (void);
|
||||||
|
|
||||||
|
asm(".weak override_func1\n.set override_func1, base_func");
|
||||||
|
asm(".set override_func1, base_func");
|
||||||
|
asm(".set override_func2, base_func");
|
||||||
|
|
||||||
|
void override_func2 (void)
|
||||||
|
{
|
||||||
|
printf ("asmc: override2\n");
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int set;
|
unsigned int set;
|
||||||
|
|
||||||
void asm_test(void)
|
void asm_test(void)
|
||||||
@ -2655,6 +2673,10 @@ void asm_test(void)
|
|||||||
unsigned int val;
|
unsigned int val;
|
||||||
struct struct123 s1;
|
struct struct123 s1;
|
||||||
struct struct1231 s2 = { (unsigned long)&s1 };
|
struct struct1231 s2 = { (unsigned long)&s1 };
|
||||||
|
/* Hide the outer base_func, but check later that the inline
|
||||||
|
asm block gets the outer one. */
|
||||||
|
int base_func = 42;
|
||||||
|
void override_func3 (void);
|
||||||
|
|
||||||
printf("inline asm:\n");
|
printf("inline asm:\n");
|
||||||
|
|
||||||
@ -2692,6 +2714,12 @@ void asm_test(void)
|
|||||||
printf("set=0x%x\n", set);
|
printf("set=0x%x\n", set);
|
||||||
val = 0x01020304;
|
val = 0x01020304;
|
||||||
printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val));
|
printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val));
|
||||||
|
override_func1();
|
||||||
|
override_func2();
|
||||||
|
/* The base_func ref from the following inline asm should find
|
||||||
|
the global one, not the local decl from this function. */
|
||||||
|
asm volatile(".weak override_func3\n.set override_func3, base_func");
|
||||||
|
override_func3();
|
||||||
return;
|
return;
|
||||||
label1:
|
label1:
|
||||||
goto label2;
|
goto label2;
|
||||||
|
Loading…
Reference in New Issue
Block a user