mirror of
https://github.com/frida/tinycc
synced 2024-12-24 22:16: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 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
|
||||
C expression parser could be tweaked to do so. */
|
||||
|
||||
@ -119,12 +158,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
||||
default:
|
||||
if (tok >= TOK_IDENT) {
|
||||
/* label case : if the label was not found, add one */
|
||||
sym = label_find(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;
|
||||
}
|
||||
sym = get_asm_sym(tok);
|
||||
if (sym->r == SHN_ABS) {
|
||||
/* if absolute symbol, no need to put a symbol value */
|
||||
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. */
|
||||
static Sym* set_symbol(TCCState *s1, int label)
|
||||
{
|
||||
Sym *sym;
|
||||
long n;
|
||||
ExprValue e;
|
||||
next();
|
||||
@ -379,7 +412,7 @@ static void asm_free_labels(TCCState *st)
|
||||
s1 = s->prev;
|
||||
/* define symbol value in object file */
|
||||
s->type.t &= ~VT_EXTERN;
|
||||
if (s->r) {
|
||||
if (s->r && !(s->type.t & VT_IMPORT)) {
|
||||
if (s->r == SHN_ABS)
|
||||
sec = SECTION_ABS;
|
||||
else
|
||||
@ -649,11 +682,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||
Sym *sym;
|
||||
|
||||
next();
|
||||
sym = label_find(tok);
|
||||
if (!sym) {
|
||||
sym = label_push(&s1->asm_labels, tok, 0);
|
||||
sym->type.t = VT_VOID | VT_EXTERN;
|
||||
}
|
||||
sym = get_asm_sym(tok);
|
||||
if (tok1 != TOK_ASMDIR_hidden)
|
||||
sym->type.t &= ~VT_STATIC;
|
||||
if (tok1 == TOK_ASMDIR_weak)
|
||||
@ -772,12 +801,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||
const char *newtype;
|
||||
|
||||
next();
|
||||
sym = label_find(tok);
|
||||
if (!sym) {
|
||||
sym = label_push(&s1->asm_labels, tok, 0);
|
||||
sym->type.t = VT_VOID | VT_EXTERN;
|
||||
}
|
||||
|
||||
sym = get_asm_sym(tok);
|
||||
next();
|
||||
skip(',');
|
||||
if (tok == TOK_STR) {
|
||||
|
@ -2647,6 +2647,24 @@ void other_constraints_test(void)
|
||||
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;
|
||||
|
||||
void asm_test(void)
|
||||
@ -2655,6 +2673,10 @@ void asm_test(void)
|
||||
unsigned int val;
|
||||
struct struct123 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");
|
||||
|
||||
@ -2692,6 +2714,12 @@ void asm_test(void)
|
||||
printf("set=0x%x\n", set);
|
||||
val = 0x01020304;
|
||||
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;
|
||||
label1:
|
||||
goto label2;
|
||||
|
Loading…
Reference in New Issue
Block a user