mirror of
https://github.com/frida/tinycc
synced 2024-12-24 05:56:49 +03:00
tccasm: Support refs to anon symbols from asm
This happens when e.g. string constants (or other static data) are passed as operands to inline asm as immediates. The produced symbol ref wouldn't be found. So tighten the connection between C and asm-local symbol table even more.
This commit is contained in:
parent
dd57a34866
commit
5bd8aeb917
13
i386-asm.c
13
i386-asm.c
@ -1437,10 +1437,19 @@ ST_FUNC void subst_asm_operand(CString *add_str,
|
||||
modifier != 'P')
|
||||
cstr_ccat(add_str, '$');
|
||||
if (r & VT_SYM) {
|
||||
cstr_cat(add_str, get_tok_str(sv->sym->v, NULL), -1);
|
||||
const char *name = get_tok_str(sv->sym->v, NULL);
|
||||
if (sv->sym->v >= SYM_FIRST_ANOM) {
|
||||
/* In case of anonymuous symbols ("L.42", used
|
||||
for static data labels) we can't find them
|
||||
in the C symbol table when later looking up
|
||||
this name. So enter them now into the asm label
|
||||
list when we still know the symbol. */
|
||||
get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym);
|
||||
}
|
||||
cstr_cat(add_str, name, -1);
|
||||
if ((uint32_t)sv->c.i == 0)
|
||||
goto no_offset;
|
||||
cstr_ccat(add_str, '+');
|
||||
cstr_ccat(add_str, '+');
|
||||
}
|
||||
val = sv->c.i;
|
||||
if (modifier == 'n')
|
||||
|
1
tcc.h
1
tcc.h
@ -1529,6 +1529,7 @@ ST_FUNC void asm_instr(void);
|
||||
ST_FUNC void asm_global_instr(void);
|
||||
#ifdef CONFIG_TCC_ASM
|
||||
ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp);
|
||||
ST_FUNC Sym* get_asm_sym(int name, Sym *csym);
|
||||
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
|
||||
ST_FUNC int asm_int_expr(TCCState *s1);
|
||||
ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess);
|
||||
|
28
tccasm.c
28
tccasm.c
@ -43,19 +43,24 @@ static Sym sym_dot;
|
||||
|
||||
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)
|
||||
symbol is initialized with info from the C symbol table.
|
||||
|
||||
If CSYM is non-null we take symbol info from it, otherwise
|
||||
we look up NAME in the C symbol table and use that. */
|
||||
ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
|
||||
{
|
||||
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;
|
||||
if (!csym) {
|
||||
csym = sym_find(name);
|
||||
/* 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 &&
|
||||
@ -63,6 +68,7 @@ static Sym* get_asm_sym(int name)
|
||||
csym->c) {
|
||||
ElfW(Sym) *esym;
|
||||
esym = &((ElfW(Sym) *)symtab_section->data)[csym->c];
|
||||
sym->c = csym->c;
|
||||
sym->r = esym->st_shndx;
|
||||
sym->jnext = esym->st_value;
|
||||
/* XXX can't yet store st_size anywhere. */
|
||||
@ -158,7 +164,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 = get_asm_sym(tok);
|
||||
sym = get_asm_sym(tok, NULL);
|
||||
if (sym->r == SHN_ABS) {
|
||||
/* if absolute symbol, no need to put a symbol value */
|
||||
pe->v = sym->jnext;
|
||||
@ -682,7 +688,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||
Sym *sym;
|
||||
|
||||
next();
|
||||
sym = get_asm_sym(tok);
|
||||
sym = get_asm_sym(tok, NULL);
|
||||
if (tok1 != TOK_ASMDIR_hidden)
|
||||
sym->type.t &= ~VT_STATIC;
|
||||
if (tok1 == TOK_ASMDIR_weak)
|
||||
@ -801,7 +807,7 @@ static void asm_parse_directive(TCCState *s1)
|
||||
const char *newtype;
|
||||
|
||||
next();
|
||||
sym = get_asm_sym(tok);
|
||||
sym = get_asm_sym(tok, NULL);
|
||||
next();
|
||||
skip(',');
|
||||
if (tok == TOK_STR) {
|
||||
|
@ -2741,6 +2741,28 @@ void override_func2 (void)
|
||||
printf ("asmc: override2\n");
|
||||
}
|
||||
|
||||
/* This checks a construct used by the linux kernel to encode
|
||||
references to strings by PC relative references. */
|
||||
extern int bug_table[] __attribute__((section("__bug_table")));
|
||||
char * get_asm_string (void)
|
||||
{
|
||||
extern int some_symbol;
|
||||
asm volatile (".globl some_symbol\n"
|
||||
"jmp .+6\n"
|
||||
"1:\n"
|
||||
"some_symbol: .long 0\n"
|
||||
".pushsection __bug_table, \"a\"\n"
|
||||
".globl bug_table\n"
|
||||
"bug_table:\n"
|
||||
/* The first entry (1b-2b) is unused in this test,
|
||||
but we include it to check if cross-section
|
||||
PC-relative references work. */
|
||||
"2:\t.long 1b - 2b, %c0 - 2b\n"
|
||||
".popsection\n" : : "i" ("A string"));
|
||||
char * str = ((char*)bug_table) + bug_table[1];
|
||||
return str;
|
||||
}
|
||||
|
||||
unsigned int set;
|
||||
|
||||
void asm_test(void)
|
||||
@ -2812,6 +2834,7 @@ void asm_test(void)
|
||||
if (!somebool)
|
||||
printf("asmbool: failed\n");
|
||||
#endif
|
||||
printf("asmstr: %s\n", get_asm_string());
|
||||
return;
|
||||
label1:
|
||||
goto label2;
|
||||
|
Loading…
Reference in New Issue
Block a user