⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tccelf.c

📁 一个GNU的C语言编译器源代码,源代码过万行.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  ELF file handling for TCC *  *  Copyright (c) 2001, 2002 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */static int put_elf_str(Section *s, const char *sym){    int offset, len;    char *ptr;    len = strlen(sym) + 1;    offset = s->data_offset;    ptr = section_ptr_add(s, len);    memcpy(ptr, sym, len);    return offset;}/* elf symbol hashing function */static unsigned long elf_hash(const unsigned char *name){    unsigned long h = 0, g;        while (*name) {        h = (h << 4) + *name++;        g = h & 0xf0000000;        if (g)            h ^= g >> 24;        h &= ~g;    }    return h;}/* rebuild hash table of section s *//* NOTE: we do factorize the hash table code to go faster */static void rebuild_hash(Section *s, unsigned int nb_buckets){    Elf32_Sym *sym;    int *ptr, *hash, nb_syms, sym_index, h;    char *strtab;    strtab = s->link->data;    nb_syms = s->data_offset / sizeof(Elf32_Sym);    s->hash->data_offset = 0;    ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int));    ptr[0] = nb_buckets;    ptr[1] = nb_syms;    ptr += 2;    hash = ptr;    memset(hash, 0, (nb_buckets + 1) * sizeof(int));    ptr += nb_buckets + 1;    sym = (Elf32_Sym *)s->data + 1;    for(sym_index = 1; sym_index < nb_syms; sym_index++) {        if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) {            h = elf_hash(strtab + sym->st_name) % nb_buckets;            *ptr = hash[h];            hash[h] = sym_index;        } else {            *ptr = 0;        }        ptr++;        sym++;    }}/* return the symbol number */static int put_elf_sym(Section *s,                        unsigned long value, unsigned long size,                       int info, int other, int shndx, const char *name){    int name_offset, sym_index;    int nbuckets, h;    Elf32_Sym *sym;    Section *hs;        sym = section_ptr_add(s, sizeof(Elf32_Sym));    if (name)        name_offset = put_elf_str(s->link, name);    else        name_offset = 0;    /* XXX: endianness */    sym->st_name = name_offset;    sym->st_value = value;    sym->st_size = size;    sym->st_info = info;    sym->st_other = other;    sym->st_shndx = shndx;    sym_index = sym - (Elf32_Sym *)s->data;    hs = s->hash;    if (hs) {        int *ptr, *base;        ptr = section_ptr_add(hs, sizeof(int));        base = (int *)hs->data;        /* only add global or weak symbols */        if (ELF32_ST_BIND(info) != STB_LOCAL) {            /* add another hashing entry */            nbuckets = base[0];            h = elf_hash(name) % nbuckets;            *ptr = base[2 + h];            base[2 + h] = sym_index;            base[1]++;            /* we resize the hash table */            hs->nb_hashed_syms++;            if (hs->nb_hashed_syms > 2 * nbuckets) {                rebuild_hash(s, 2 * nbuckets);            }        } else {            *ptr = 0;            base[1]++;        }    }    return sym_index;}/* find global ELF symbol 'name' and return its index. Return 0 if not   found. */static int find_elf_sym(Section *s, const char *name){    Elf32_Sym *sym;    Section *hs;    int nbuckets, sym_index, h;    const char *name1;        hs = s->hash;    if (!hs)        return 0;    nbuckets = ((int *)hs->data)[0];    h = elf_hash(name) % nbuckets;    sym_index = ((int *)hs->data)[2 + h];    while (sym_index != 0) {        sym = &((Elf32_Sym *)s->data)[sym_index];        name1 = s->link->data + sym->st_name;        if (!strcmp(name, name1))            return sym_index;        sym_index = ((int *)hs->data)[2 + nbuckets + sym_index];    }    return 0;}/* return elf symbol value or error */int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name){    int sym_index;    Elf32_Sym *sym;        sym_index = find_elf_sym(symtab_section, name);    if (!sym_index)        return -1;    sym = &((Elf32_Sym *)symtab_section->data)[sym_index];    *pval = sym->st_value;    return 0;}void *tcc_get_symbol_err(TCCState *s, const char *name){    unsigned long val;    if (tcc_get_symbol(s, &val, name) < 0)        error("%s not defined", name);    return (void *)val;}/* add an elf symbol : check if it is already defined and patch   it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */static int add_elf_sym(Section *s, unsigned long value, unsigned long size,                       int info, int sh_num, const char *name){    Elf32_Sym *esym;    int sym_bind, sym_index, sym_type, esym_bind;    sym_bind = ELF32_ST_BIND(info);    sym_type = ELF32_ST_TYPE(info);            if (sym_bind != STB_LOCAL) {        /* we search global or weak symbols */        sym_index = find_elf_sym(s, name);        if (!sym_index)            goto do_def;        esym = &((Elf32_Sym *)s->data)[sym_index];        if (esym->st_shndx != SHN_UNDEF) {            esym_bind = ELF32_ST_BIND(esym->st_info);            if (sh_num == SHN_UNDEF) {                /* ignore adding of undefined symbol if the                   corresponding symbol is already defined */            } else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) {                /* global overrides weak, so patch */                goto do_patch;            } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) {                /* weak is ignored if already global */            } else {#if 0                printf("new_bind=%d new_shndx=%d last_bind=%d old_shndx=%d\n",                       sym_bind, sh_num, esym_bind, esym->st_shndx);#endif                /* NOTE: we accept that two DLL define the same symbol */                if (s != tcc_state->dynsymtab_section)                    error_noabort("'%s' defined twice", name);            }        } else {        do_patch:            esym->st_info = ELF32_ST_INFO(sym_bind, sym_type);            esym->st_shndx = sh_num;            esym->st_value = value;            esym->st_size = size;        }    } else {    do_def:        sym_index = put_elf_sym(s, value, size,                                 ELF32_ST_INFO(sym_bind, sym_type), 0,                                 sh_num, name);    }    return sym_index;}/* put relocation */static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,                          int type, int symbol){    char buf[256];    Section *sr;    Elf32_Rel *rel;    sr = s->reloc;    if (!sr) {        /* if no relocation section, create it */        snprintf(buf, sizeof(buf), ".rel%s", s->name);        /* if the symtab is allocated, then we consider the relocation           are also */        sr = new_section(tcc_state, buf, SHT_REL, symtab->sh_flags);        sr->sh_entsize = sizeof(Elf32_Rel);        sr->link = symtab;        sr->sh_info = s->sh_num;        s->reloc = sr;    }    rel = section_ptr_add(sr, sizeof(Elf32_Rel));    rel->r_offset = offset;    rel->r_info = ELF32_R_INFO(symbol, type);}/* put stab debug information */typedef struct {    unsigned long n_strx;         /* index into string table of name */    unsigned char n_type;         /* type of symbol */    unsigned char n_other;        /* misc info (usually empty) */    unsigned short n_desc;        /* description field */    unsigned long n_value;        /* value of symbol */} Stab_Sym;static void put_stabs(const char *str, int type, int other, int desc,                       unsigned long value){    Stab_Sym *sym;    sym = section_ptr_add(stab_section, sizeof(Stab_Sym));    if (str) {        sym->n_strx = put_elf_str(stabstr_section, str);    } else {        sym->n_strx = 0;    }    sym->n_type = type;    sym->n_other = other;    sym->n_desc = desc;    sym->n_value = value;}static void put_stabs_r(const char *str, int type, int other, int desc,                         unsigned long value, Section *sec, int sym_index){    put_stabs(str, type, other, desc, value);    put_elf_reloc(symtab_section, stab_section,                   stab_section->data_offset - sizeof(unsigned long),                  R_DATA_32, sym_index);}static void put_stabn(int type, int other, int desc, int value){    put_stabs(NULL, type, other, desc, value);}static void put_stabd(int type, int other, int desc){    put_stabs(NULL, type, other, desc, 0);}/* In an ELF file symbol table, the local symbols must appear below   the global and weak ones. Since TCC cannot sort it while generating   the code, we must do it after. All the relocation tables are also   modified to take into account the symbol table sorting */static void sort_syms(TCCState *s1, Section *s){    int *old_to_new_syms;    Elf32_Sym *new_syms;    int nb_syms, i;    Elf32_Sym *p, *q;    Elf32_Rel *rel, *rel_end;    Section *sr;    int type, sym_index;    nb_syms = s->data_offset / sizeof(Elf32_Sym);    new_syms = tcc_malloc(nb_syms * sizeof(Elf32_Sym));    old_to_new_syms = tcc_malloc(nb_syms * sizeof(int));    /* first pass for local symbols */    p = (Elf32_Sym *)s->data;    q = new_syms;    for(i = 0; i < nb_syms; i++) {        if (ELF32_ST_BIND(p->st_info) == STB_LOCAL) {            old_to_new_syms[i] = q - new_syms;            *q++ = *p;        }        p++;    }    /* save the number of local symbols in section header */    s->sh_info = q - new_syms;    /* then second pass for non local symbols */    p = (Elf32_Sym *)s->data;    for(i = 0; i < nb_syms; i++) {        if (ELF32_ST_BIND(p->st_info) != STB_LOCAL) {            old_to_new_syms[i] = q - new_syms;            *q++ = *p;        }        p++;    }        /* we copy the new symbols to the old */    memcpy(s->data, new_syms, nb_syms * sizeof(Elf32_Sym));    tcc_free(new_syms);    /* now we modify all the relocations */    for(i = 1; i < s1->nb_sections; i++) {        sr = s1->sections[i];        if (sr->sh_type == SHT_REL && sr->link == s) {            rel_end = (Elf32_Rel *)(sr->data + sr->data_offset);            for(rel = (Elf32_Rel *)sr->data;                rel < rel_end;                rel++) {                sym_index = ELF32_R_SYM(rel->r_info);                type = ELF32_R_TYPE(rel->r_info);                sym_index = old_to_new_syms[sym_index];                rel->r_info = ELF32_R_INFO(sym_index, type);            }        }    }        tcc_free(old_to_new_syms);}/* relocate common symbols in the .bss section */static void relocate_common_syms(void){    Elf32_Sym *sym, *sym_end;    unsigned long offset, align;        sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset);    for(sym = (Elf32_Sym *)symtab_section->data + 1;         sym < sym_end;        sym++) {        if (sym->st_shndx == SHN_COMMON) {            /* align symbol */            align = sym->st_value;            offset = bss_section->data_offset;            offset = (offset + align - 1) & -align;            sym->st_value = offset;            sym->st_shndx = bss_section->sh_num;            offset += sym->st_size;            bss_section->data_offset = offset;        }    }}static void *resolve_sym(const char *sym){    return dlsym(RTLD_DEFAULT, sym);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -