Alien-TinyCCx
view release on metacpan or search on metacpan
src/tccexsymtab.c view on Meta::CPAN
{
Section * s;
ElfW(Sym) *sym;
int sym_index;
const char *name;
s = state->symtab;
sym_index = 2;
sym = &((ElfW(Sym) *)s->data)[sym_index];
name = s->link->data + sym->st_name;
while (strcmp("_etext", name) != 0) {
printf("%s: sym_index = %d, st_shndx is %x, address is %p\n", name, sym_index, sym->st_shndx, (void*)sym->st_value);
sym_index++;
sym = &((ElfW(Sym) *)s->data)[sym_index];
name = s->link->data + sym->st_name;
}
}
char * type_lookup_table[16] = {
"int", "char", "short", "void",
"pointer", "enum", "func", "struct",
"float", "double", "long double", "bool",
"long long", "long", "qlong", "qfloat"
};
void tcc_dump_identifier_names(extended_symtab * symtab, char * outfile)
{
int i;
FILE * out_fh = fopen(outfile, "w");
/* report error? I think a lack of file will probably be sufficient */
if (!out_fh) return;
for (i = 0; symtab->tokenSym_list + i < symtab->tokenSym_last; i++) {
int btype;
TokenSym * ts;
Sym * curr_sym;
ts = symtab->tokenSym_list[i];
if (!ts->sym_identifier) continue;
curr_sym = ts->sym_identifier;
/* only indicate the things that have external linkage */
if ((curr_sym->type.t & (VT_EXTERN | VT_STATIC)) != VT_EXTERN) continue;
if (curr_sym->type.t & VT_TYPEDEF) continue;
/* name */
fprintf(out_fh, "%s ", ts->str);
/* qualifiers */
if (curr_sym->type.t & VT_CONSTANT) fprintf(out_fh, "constant ");
/* type */
btype = curr_sym->type.t & VT_BTYPE;
fprintf(out_fh, "%s\n", type_lookup_table[btype]);
}
fclose(out_fh);
}
/* tcc_get_next_extended_symbol_name: a simple mechanism for getting the names
* of all of the global symbols known to the extended symbol table. */
char * tcc_get_next_extended_symbol_name(extended_symtab * symtab, int * poffset)
{
/* Increment the counter to get to the next TokenSym */
for ((*poffset)++; symtab->tokenSym_list + *poffset < symtab->tokenSym_last; (*poffset)++)
{
TokenSym * ts = symtab->tokenSym_list[*poffset];
if (ts->sym_identifier) return ts->str;
}
/* Reached end of list. Reset the counter and return null */
*poffset = -1;
return NULL;
}
void copy_extended_symbols_to_exsymtab(TCCState *state)
{
Section * s;
ElfW(Sym) *sym;
int sym_index;
const char *name;
extended_symtab* exsymtab;
exsymtab = state->exsymtab;
s = state->symtab;
sym_index = 2;
sym = &((ElfW(Sym) *)s->data)[sym_index];
name = s->link->data + sym->st_name;
while (strcmp("_etext", name) != 0) {
if (name[0] == 'L' && name[1] == '.') {
/* Skip constants */
}
else {
/* Copy the symbol's pointer into the hash_next field of the TokenSym */
TokenSym * ts = tcc_get_extended_tokensym(exsymtab, name);
if (ts == NULL) {
tcc_warning("Global symbol %s does not exist in extended symbol table; not copying\n",
name);
}
else {
ts->hash_next = (void*)sym->st_value;
}
}
/* Next iteration */
sym_index++;
sym = &((ElfW(Sym) *)s->data)[sym_index];
name = s->link->data + sym->st_name;
}
}
/* A value of NULL for exsymtab means that the extended symtab was not supposed
* to be generated in the first place. A value of 1 means that it is supposed to
* be created, but the state hasn't compiled yet. Otherwise, we have a fully
* formed extended symbol table, which we can return. In that case, we assume
* that the user takes responsibility for cleaning it up. */
LIBTCCAPI extended_symtab * tcc_get_extended_symbol_table(TCCState * s)
{
extended_symtab * to_return;
if (s->exsymtab <= (extended_symtab*)1) return NULL;
/* clear the pointer value; otherwise we would free it, leading to a
* double-free situation when the user also frees it. */
to_return = s->exsymtab;
s->exsymtab = (extended_symtab*)1;
return to_return;
}
LIBTCCAPI TokenSym* tcc_get_extended_tokensym(extended_symtab* symtab, const char * name)
{
/* delegate to the symtab's trie */
return (TokenSym*)(*token_string_hash_get_ref(symtab->tsh, name));
}
LIBTCCAPI void * tcc_get_extended_symbol(extended_symtab * symtab, const char * name)
{
TokenSym * ts = tcc_get_extended_tokensym(symtab, name);
if (ts == NULL) return NULL;
return (void*) ts->hash_next;
}
/******************************************************************************/
/* extended symtab copy */
/******************************************************************************/
/* The user may want fine-grained control over the order of symbol table lookup.
* Thus, I provide a set of callbacks to look for names, add symbols to compiler
* contexts, and prep the compiler state before things get started. */
LIBTCCAPI void tcc_set_extended_symtab_callbacks (
TCCState * s,
extended_symtab_lookup_by_name_callback new_name_callback,
extended_symtab_sym_used_callback new_sym_used_callback,
extended_symtab_prep_callback new_prep_callback,
void * data
) {
s->symtab_name_callback = new_name_callback;
s->symtab_sym_used_callback = new_sym_used_callback;
s->symtab_prep_callback = new_prep_callback;
s->symtab_callback_data = data;
}
LIBTCCAPI void tcc_save_extended_symtab(TCCState * s) {
if (s->exsymtab == NULL) s->exsymtab = (extended_symtab*)1;
}
Sym * get_new_symtab_pointer (Sym * old, ram_hash * rh)
{
void ** Sym_ref;
Sym * to_return;
int btype;
/* Handle the null case up-front */
if (old == NULL) return NULL;
/* Check the global symbol stack. */
Sym_ref = ram_hash_get_ref(rh, old);
to_return = *Sym_ref;
if (NULL != to_return) return to_return;
/* Create new sym. Note that mallocz sets lots of things to null
* for me. :-) */
to_return = *Sym_ref = tcc_mallocz(sizeof(Sym));
/* See tcc.h around line 425 for descriptions of some of the fields.
* See also tccgen.c line 5987 to see what needs to happen for function
* declarations to work properly (and, in turn, line 446 for how to
* push a forward reference). */
/* Copy the v value (token id). This will not be copied later, so keep
* things simple for now and simply strip out the extended flag. */
to_return->v = old->v & ~SYM_EXTENDED;
/* Copy the assembler label token id. Just like the v field, we copy
* this unmodified. */
/* XXX do we need to strip out SYM_EXTENDED? It seems unlikely. */
to_return->asm_label = old->asm_label;
/* associated register. For variables, I believe that the low bits
* specify the register size that can hold the value while high bits
* indicate storage details (VT_SYM, VT_LVAL, etc). For function types,
* however, this gets cast as an AttributeDef and queried for function
* attributes; so far, I have only seen the .r field queried for the
* FUNC_CALL field. It matters little; copying the whole long is easy
* and it seems that everything works fine when it is the same for
* consuming contexts as for the original compilation context. */
to_return->r = old->r;
/* Set the type. Judging by the constants in tcc.h and code that
* uses this field, I'm pretty sure that the low bits in the .t field
* tells tcc how to load the data into a register. The high bits seem to
* indicate storage details, such as VT_EXTERN. Since that is not
* something that can be extended at runtime, I should be able to copy
* the value as-is and add an extern flag for variables and functions. */
to_return->type.t = old->type.t;
/* After compilation, functions and global variables point to hard
* locations in memory. Consuming contexts should think of these as
* having external storage, which is reflected in the VT_EXTERN bit of
* the type.t field. */
btype = old->type.t & VT_BTYPE;
if (btype == VT_FUNC || to_return->r & (VT_SYM | VT_LVAL))
to_return->type.t |= VT_EXTERN;
/* Remove static indicator from functions */
if ((btype == VT_FUNC) && (old->type.t & VT_STATIC))
to_return->type.t &= ~VT_STATIC;
/* Static inline functions are the exception to this rule, so undo
* the above work for them. */
if ((old->type.t & (VT_INLINE | VT_STATIC)) == (VT_INLINE | VT_STATIC))
to_return->type.t = old->type.t;
/* The type.ref field contains something useful only if the basic type
* is a pointer, struct, enum, or function. See code from tccgen's
* compare_types for details. */
if (btype == VT_PTR || btype == VT_STRUCT || btype == VT_ENUM || btype == VT_FUNC) {
to_return->type.ref = get_new_symtab_pointer(old->type.ref, rh);
}
/* Copy the c field, the "associated number." According to tcc-doc.texi
* as well as the comments just above the definition of put_extern_sym2,
* the c field will (for some Syms) point to an external symbol in an
* associated section. But this is not true for all Syms. For structs,
* this is the size (in bytes), and for struct members it is the byte
* offset of the member, according to the end of struct_decl(). For
* variable length arrays, this is "the location on the stack that holds
* the runtime sizeof for the type." For functions, I believe this is
* one of FUNC_NEW, FUNC_OLD, or FUNC_ELLIPSIS. At any rate, everything
* seems to work if I simply set it to zero for functions and global
* variables and copy it otherwise, so I'm going with that. This probably
* needs to be more nuanced. */
if (btype == VT_FUNC || to_return->r & (VT_SYM | VT_LVAL))
to_return->c = 0;
else
to_return->c = old->c;
/* Copy the next symbol field. Labels and gotos are tracked in a
* separate stack, so for these Symbols we focus on next, not
* jnext. The next field (I seem to recall) is used in storing
* argument lists, so it needs to be copied for function
* types. I believe it can be copied anonymously. */
to_return->next = get_new_symtab_pointer(old->next, rh);
return to_return;
}
Sym * get_new_deftab_pointer (Sym * old, ram_hash * rh)
{
void ** Sym_ref;
Sym * to_return;
/* Handle the null case up-front */
if (old == NULL) return NULL;
/* Does this exist in the ram hash? */
Sym_ref = ram_hash_get_ref(rh, old);
to_return = *Sym_ref;
if (to_return != NULL) return to_return;
/* Create a new define object. See symtab pointer copy above for
* descriptions of some of the fields. */
to_return = *Sym_ref = tcc_mallocz(sizeof(Sym));
/* Convert the symbol's token index. */
to_return->v = old->v & ~SYM_EXTENDED;
/* As far as I can tell, the 'r' field is not used by
* preprocessor macros. Just copy it in the off-chance I'm wrong. */
to_return->r = old->r;
/* Copy the tokenstream if it exists */
if (old->d != NULL) {
int * str = old->d;
int len = tokenstream_len(str);
to_return->d = tcc_malloc(sizeof(int) * len);
/* The extended symbol table's token ids are identical to the
* originals, so we can just copy the token stream verbatim! */
memcpy(to_return->d, old->d, sizeof(int) * len);
}
/* Set the type. define_push and parse_define indicate that this
* will be either MACRO_OBJ or MACRO_FUNC. */
to_return->type.t = old->type.t;
/* Copy the macro arguments. */
to_return->next = get_new_deftab_pointer(old->next, rh);
return to_return;
( run in 0.707 second using v1.01-cache-2.11-cpan-13bb782fe5a )