added archive support - better ELF output - fixed symbol relocation - added COMMON symbol handling
This commit is contained in:
		
							parent
							
								
									f75e0c6d62
								
							
						
					
					
						commit
						7b54a53e08
					
				
					 1 changed files with 418 additions and 238 deletions
				
			
		
							
								
								
									
										550
									
								
								tcc.c
									
										
									
									
									
								
							
							
						
						
									
										550
									
								
								tcc.c
									
										
									
									
									
								
							| 
						 | 
					@ -6314,33 +6314,13 @@ static unsigned long elf_hash(const unsigned char *name)
 | 
				
			||||||
    return h;
 | 
					    return h;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* add one symbol in hash table if it is global */
 | 
					 | 
				
			||||||
/* WARNING: must be called each time a symbol is added otherwise the
 | 
					 | 
				
			||||||
   hash table is not synchronized with the symbol table */
 | 
					 | 
				
			||||||
static void update_hash_elf_sym(Section *hs, 
 | 
					 | 
				
			||||||
                                int sym_index, int info, const char *name)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int nbuckets, h;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* only add global symbols */
 | 
					 | 
				
			||||||
    if (ELF32_ST_BIND(info) == STB_GLOBAL) {
 | 
					 | 
				
			||||||
        /* add another hashing entry */
 | 
					 | 
				
			||||||
        nbuckets = ((int *)hs->data)[0];
 | 
					 | 
				
			||||||
        h = elf_hash(name) % nbuckets;
 | 
					 | 
				
			||||||
        ((int *)hs->data)[2 + nbuckets + sym_index] = ((int *)hs->data)[2 + h];
 | 
					 | 
				
			||||||
        ((int *)hs->data)[2 + h] = sym_index;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    /* but still add room for all symbols */
 | 
					 | 
				
			||||||
    ((int *)hs->data)[1]++;
 | 
					 | 
				
			||||||
    hs->data_ptr += sizeof(int);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* return the symbol number */
 | 
					/* return the symbol number */
 | 
				
			||||||
static int put_elf_sym(Section *s, 
 | 
					static int put_elf_sym(Section *s, 
 | 
				
			||||||
                       unsigned long value, unsigned long size,
 | 
					                       unsigned long value, unsigned long size,
 | 
				
			||||||
                       int info, int other, int shndx, const char *name)
 | 
					                       int info, int other, int shndx, const char *name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int name_offset, sym_index;
 | 
					    int name_offset, sym_index;
 | 
				
			||||||
 | 
					    int nbuckets, h;
 | 
				
			||||||
    Elf32_Sym *sym;
 | 
					    Elf32_Sym *sym;
 | 
				
			||||||
    Section *hs;
 | 
					    Section *hs;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					@ -6359,7 +6339,17 @@ static int put_elf_sym(Section *s,
 | 
				
			||||||
    sym_index = sym - (Elf32_Sym *)s->data;
 | 
					    sym_index = sym - (Elf32_Sym *)s->data;
 | 
				
			||||||
    hs = s->hash;
 | 
					    hs = s->hash;
 | 
				
			||||||
    if (hs) {
 | 
					    if (hs) {
 | 
				
			||||||
        update_hash_elf_sym(hs, sym_index, info, name);
 | 
					        /* only add global or weak symbols */
 | 
				
			||||||
 | 
					        if (ELF32_ST_BIND(info) != STB_LOCAL) {
 | 
				
			||||||
 | 
					            /* add another hashing entry */
 | 
				
			||||||
 | 
					            nbuckets = ((int *)hs->data)[0];
 | 
				
			||||||
 | 
					            h = elf_hash(name) % nbuckets;
 | 
				
			||||||
 | 
					            ((int *)hs->data)[2 + nbuckets + sym_index] = ((int *)hs->data)[2 + h];
 | 
				
			||||||
 | 
					            ((int *)hs->data)[2 + h] = sym_index;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /* but still add room for all symbols */
 | 
				
			||||||
 | 
					        ((int *)hs->data)[1]++;
 | 
				
			||||||
 | 
					        hs->data_ptr += sizeof(int);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    s->data_ptr += sizeof(Elf32_Sym);
 | 
					    s->data_ptr += sizeof(Elf32_Sym);
 | 
				
			||||||
    return sym_index;
 | 
					    return sym_index;
 | 
				
			||||||
| 
						 | 
					@ -6390,12 +6380,74 @@ static int find_elf_sym(Section *s, const char *name)
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* return elf symbol value or error */
 | 
				
			||||||
 | 
					static unsigned long get_elf_sym_val(const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int sym_index;
 | 
				
			||||||
 | 
					    Elf32_Sym *sym;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    sym_index = find_elf_sym(symtab_section, name);
 | 
				
			||||||
 | 
					    if (!sym_index)
 | 
				
			||||||
 | 
					        error("%s not defined", name);
 | 
				
			||||||
 | 
					    sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
 | 
				
			||||||
 | 
					    return sym->st_value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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(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(symtab_section, name);
 | 
				
			||||||
 | 
					        if (!sym_index)
 | 
				
			||||||
 | 
					            goto do_def;
 | 
				
			||||||
 | 
					        esym = &((Elf32_Sym *)symtab_section->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
 | 
				
			||||||
 | 
					                error("'%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(symtab_section, value, size, 
 | 
				
			||||||
 | 
					                                ELF32_ST_INFO(sym_bind, sym_type), 0, 
 | 
				
			||||||
 | 
					                                sh_num, name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return sym_index;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* update sym->c so that it points to an external symbol in section
 | 
					/* update sym->c so that it points to an external symbol in section
 | 
				
			||||||
   'section' with value 'value' */
 | 
					   'section' with value 'value' */
 | 
				
			||||||
/* XXX: get rid of put_elf_sym */
 | 
					 | 
				
			||||||
void put_extern_sym(Sym *sym, Section *section, unsigned long value)
 | 
					void put_extern_sym(Sym *sym, Section *section, unsigned long value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int sym_type, sym_bind, sh_num;
 | 
					    int sym_type, sym_bind, sh_num, info;
 | 
				
			||||||
    Elf32_Sym *esym;
 | 
					    Elf32_Sym *esym;
 | 
				
			||||||
    const char *name;
 | 
					    const char *name;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					@ -6412,27 +6464,9 @@ void put_extern_sym(Sym *sym, Section *section, unsigned long value)
 | 
				
			||||||
            sym_bind = STB_LOCAL;
 | 
					            sym_bind = STB_LOCAL;
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            sym_bind = STB_GLOBAL;
 | 
					            sym_bind = STB_GLOBAL;
 | 
				
			||||||
        /* if the symbol is global, then we look if it is already
 | 
					 | 
				
			||||||
           defined */
 | 
					 | 
				
			||||||
        name = get_tok_str(sym->v, NULL);
 | 
					        name = get_tok_str(sym->v, NULL);
 | 
				
			||||||
        if (sym_bind == STB_GLOBAL) {
 | 
					        info = ELF32_ST_INFO(sym_bind, sym_type);
 | 
				
			||||||
            sym->c = find_elf_sym(symtab_section, name);
 | 
					        sym->c = add_elf_sym(value, 0, info, sh_num, name);
 | 
				
			||||||
            if (!sym->c)
 | 
					 | 
				
			||||||
                goto do_def;
 | 
					 | 
				
			||||||
            /* check if not defined */
 | 
					 | 
				
			||||||
            if (section) {
 | 
					 | 
				
			||||||
                esym = &((Elf32_Sym *)symtab_section->data)[sym->c];
 | 
					 | 
				
			||||||
                if (esym->st_shndx != SHN_UNDEF)
 | 
					 | 
				
			||||||
                    error("'%s' defined twice", name);
 | 
					 | 
				
			||||||
                esym->st_shndx = sh_num;
 | 
					 | 
				
			||||||
                esym->st_value = value;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
        do_def:
 | 
					 | 
				
			||||||
            sym->c = put_elf_sym(symtab_section, value, 0, 
 | 
					 | 
				
			||||||
                                 ELF32_ST_INFO(sym_bind, sym_type), 0, 
 | 
					 | 
				
			||||||
                                 sh_num, name);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        esym = &((Elf32_Sym *)symtab_section->data)[sym->c];
 | 
					        esym = &((Elf32_Sym *)symtab_section->data)[sym->c];
 | 
				
			||||||
        esym->st_value = value;
 | 
					        esym->st_value = value;
 | 
				
			||||||
| 
						 | 
					@ -6509,7 +6543,7 @@ static void put_stabd(int type, int other, int desc)
 | 
				
			||||||
   the global and weak ones. Since TCC cannot sort it while generating
 | 
					   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
 | 
					   the code, we must do it after. All the relocation tables are also
 | 
				
			||||||
   modified to take into account the symbol table sorting */
 | 
					   modified to take into account the symbol table sorting */
 | 
				
			||||||
static void sort_symbols(Section *s)
 | 
					static void sort_syms(Section *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int *old_to_new_syms;
 | 
					    int *old_to_new_syms;
 | 
				
			||||||
    Elf32_Sym *new_syms;
 | 
					    Elf32_Sym *new_syms;
 | 
				
			||||||
| 
						 | 
					@ -6570,16 +6604,78 @@ static void sort_symbols(Section *s)
 | 
				
			||||||
    free(old_to_new_syms);
 | 
					    free(old_to_new_syms);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned long get_sym_val(int sym_index)
 | 
					/* relocate common symbols in the .bss section */
 | 
				
			||||||
 | 
					static void relocate_common_syms(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    unsigned long val;
 | 
					 | 
				
			||||||
    Elf32_Sym *sym;
 | 
					    Elf32_Sym *sym;
 | 
				
			||||||
 | 
					    unsigned long offset, align;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
 | 
					    for(sym = (Elf32_Sym *)symtab_section->data + 1; 
 | 
				
			||||||
    val = sym->st_value;
 | 
					        sym < (Elf32_Sym *)symtab_section->data_ptr;
 | 
				
			||||||
    if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
 | 
					        sym++) {
 | 
				
			||||||
        val += sections[sym->st_shndx]->sh_addr;
 | 
					        if (sym->st_shndx == SHN_COMMON) {
 | 
				
			||||||
    return val;
 | 
					            /* align symbol */
 | 
				
			||||||
 | 
					            align = sym->st_value;
 | 
				
			||||||
 | 
					            offset = bss_section->data_ptr - bss_section->data;
 | 
				
			||||||
 | 
					            offset = (offset + align - 1) & -align;
 | 
				
			||||||
 | 
					            sym->st_value = offset;
 | 
				
			||||||
 | 
					            sym->st_shndx = bss_section->sh_num;
 | 
				
			||||||
 | 
					            offset += sym->st_size;
 | 
				
			||||||
 | 
					            bss_section->data_ptr = bss_section->data + offset;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *resolve_sym(const char *sym)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCC_BCHECK
 | 
				
			||||||
 | 
					    if (do_bounds_check) {
 | 
				
			||||||
 | 
					        void *ptr;
 | 
				
			||||||
 | 
					        ptr = bound_resolve_sym(sym);
 | 
				
			||||||
 | 
					        if (ptr)
 | 
				
			||||||
 | 
					            return ptr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    return dlsym(NULL, sym);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* relocate symbol table, resolve undefined symbols if do_resolve is
 | 
				
			||||||
 | 
					   true and output error if undefined symbol. */
 | 
				
			||||||
 | 
					static void relocate_syms(int do_resolve)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Elf32_Sym *sym;
 | 
				
			||||||
 | 
					    int sym_bind, sh_num;
 | 
				
			||||||
 | 
					    const char *name;
 | 
				
			||||||
 | 
					    unsigned long addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(sym = (Elf32_Sym *)symtab_section->data + 1; 
 | 
				
			||||||
 | 
					        sym < (Elf32_Sym *)symtab_section->data_ptr;
 | 
				
			||||||
 | 
					        sym++) {
 | 
				
			||||||
 | 
					        sh_num = sym->st_shndx;
 | 
				
			||||||
 | 
					        if (sh_num == SHN_UNDEF) {
 | 
				
			||||||
 | 
					            name = strtab_section->data + sym->st_name;
 | 
				
			||||||
 | 
					            if (do_resolve) {
 | 
				
			||||||
 | 
					                name = symtab_section->link->data + sym->st_name;
 | 
				
			||||||
 | 
					                addr = (unsigned long)resolve_sym(name);
 | 
				
			||||||
 | 
					                if (addr) {
 | 
				
			||||||
 | 
					                    sym->st_value = addr;
 | 
				
			||||||
 | 
					                    goto found;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            /* only weak symbols are accepted to be undefined. Their value is zero */
 | 
				
			||||||
 | 
					            sym_bind = ELF32_ST_BIND(sym->st_info);
 | 
				
			||||||
 | 
					            if (sym_bind == STB_WEAK) {
 | 
				
			||||||
 | 
					                sym->st_value = 0;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                //                error("undefined symbol '%s'", name);
 | 
				
			||||||
 | 
					                warning("undefined symbol '%s'", name);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (sh_num < SHN_LORESERVE) {
 | 
				
			||||||
 | 
					            /* add section base */
 | 
				
			||||||
 | 
					            sym->st_value += sections[sym->st_shndx]->sh_addr;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    found: ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* relocate a given section */
 | 
					/* relocate a given section */
 | 
				
			||||||
| 
						 | 
					@ -6587,6 +6683,7 @@ static void relocate_section(Section *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Section *sr;
 | 
					    Section *sr;
 | 
				
			||||||
    Elf32_Rel *rel;
 | 
					    Elf32_Rel *rel;
 | 
				
			||||||
 | 
					    Elf32_Sym *sym;
 | 
				
			||||||
    int type;
 | 
					    int type;
 | 
				
			||||||
    unsigned char *ptr;
 | 
					    unsigned char *ptr;
 | 
				
			||||||
    unsigned long val;
 | 
					    unsigned long val;
 | 
				
			||||||
| 
						 | 
					@ -6596,7 +6693,9 @@ static void relocate_section(Section *s)
 | 
				
			||||||
        rel < (Elf32_Rel *)sr->data_ptr;
 | 
					        rel < (Elf32_Rel *)sr->data_ptr;
 | 
				
			||||||
        rel++) {
 | 
					        rel++) {
 | 
				
			||||||
        ptr = s->data + rel->r_offset;
 | 
					        ptr = s->data + rel->r_offset;
 | 
				
			||||||
        val = get_sym_val(ELF32_R_SYM(rel->r_info));
 | 
					
 | 
				
			||||||
 | 
					        sym = &((Elf32_Sym *)symtab_section->data)[ELF32_R_SYM(rel->r_info)];
 | 
				
			||||||
 | 
					        val = sym->st_value;
 | 
				
			||||||
        type = ELF32_R_TYPE(rel->r_info);
 | 
					        type = ELF32_R_TYPE(rel->r_info);
 | 
				
			||||||
        greloc_patch(ptr, s->sh_addr + rel->r_offset, val, type);
 | 
					        greloc_patch(ptr, s->sh_addr + rel->r_offset, val, type);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -6669,7 +6768,20 @@ int tcc_output_file(TCCState *s1, const char *filename, int file_type)
 | 
				
			||||||
    dynstr = NULL; /* avoid warning */
 | 
					    dynstr = NULL; /* avoid warning */
 | 
				
			||||||
    saved_dynamic_data_ptr = NULL; /* avoid warning */
 | 
					    saved_dynamic_data_ptr = NULL; /* avoid warning */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (file_type != TCC_FILE_OBJ && !static_link) {
 | 
					    if (file_type != TCC_FILE_OBJ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        relocate_common_syms();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* a got is needed even if static link for the symbol
 | 
				
			||||||
 | 
					           _GLOBAL_OFFSET_TABLE_ */
 | 
				
			||||||
 | 
					        got = new_section(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
 | 
				
			||||||
 | 
					        got->sh_entsize = 4;
 | 
				
			||||||
 | 
					        add_elf_sym(0, 4, ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT), 
 | 
				
			||||||
 | 
					                    got->sh_num, "_GLOBAL_OFFSET_TABLE_");
 | 
				
			||||||
 | 
					        /* keep space for _DYNAMIC pointer, if present */
 | 
				
			||||||
 | 
					        got->data_ptr += 4;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (!static_link) {
 | 
				
			||||||
            const char *name;
 | 
					            const char *name;
 | 
				
			||||||
            int nb_plt_entries;
 | 
					            int nb_plt_entries;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
| 
						 | 
					@ -6702,8 +6814,6 @@ int tcc_output_file(TCCState *s1, const char *filename, int file_type)
 | 
				
			||||||
            /* add PLT and GOT */
 | 
					            /* add PLT and GOT */
 | 
				
			||||||
            plt = new_section(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
 | 
					            plt = new_section(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
 | 
				
			||||||
            plt->sh_entsize = 4;
 | 
					            plt->sh_entsize = 4;
 | 
				
			||||||
        got = new_section(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
 | 
					 | 
				
			||||||
        got->sh_entsize = 4;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /* add undefined symbols in dynamic symbol table */
 | 
					            /* add undefined symbols in dynamic symbol table */
 | 
				
			||||||
            nb_plt_entries = 0;
 | 
					            nb_plt_entries = 0;
 | 
				
			||||||
| 
						 | 
					@ -6725,7 +6835,7 @@ int tcc_output_file(TCCState *s1, const char *filename, int file_type)
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
            /* update PLT/GOT sizes so that we can allocate their space */
 | 
					            /* update PLT/GOT sizes so that we can allocate their space */
 | 
				
			||||||
            plt->data_ptr += 16 * (nb_plt_entries + 1);
 | 
					            plt->data_ptr += 16 * (nb_plt_entries + 1);
 | 
				
			||||||
        got->data_ptr += 4 * (nb_plt_entries + 3);
 | 
					            got->data_ptr += 4 * (nb_plt_entries + 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, "libc.so.6"));
 | 
					            put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, "libc.so.6"));
 | 
				
			||||||
            /* XXX: add other libs */
 | 
					            /* XXX: add other libs */
 | 
				
			||||||
| 
						 | 
					@ -6734,8 +6844,7 @@ int tcc_output_file(TCCState *s1, const char *filename, int file_type)
 | 
				
			||||||
            saved_dynamic_data_ptr = dynamic->data_ptr;
 | 
					            saved_dynamic_data_ptr = dynamic->data_ptr;
 | 
				
			||||||
            dynamic->data_ptr += 8 * 9;
 | 
					            dynamic->data_ptr += 8 * 9;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    sort_symbols(symtab_section);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memset(&ehdr, 0, sizeof(ehdr));
 | 
					    memset(&ehdr, 0, sizeof(ehdr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6967,17 +7076,22 @@ int tcc_output_file(TCCState *s1, const char *filename, int file_type)
 | 
				
			||||||
            file_offset += s->sh_size;
 | 
					            file_offset += s->sh_size;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
#if 1
 | 
					    /* if building executable or DLL, then relocate each section
 | 
				
			||||||
    /* if building executable, then relocate each section except the GOT
 | 
					       except the GOT which is already relocated */
 | 
				
			||||||
       which is already relocated */
 | 
					    if (file_type != TCC_FILE_OBJ) {
 | 
				
			||||||
    if (file_type == TCC_FILE_EXE) {
 | 
					        relocate_syms(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for(i = 1; i < nb_sections; i++) {
 | 
					        for(i = 1; i < nb_sections; i++) {
 | 
				
			||||||
            s = sections[i];
 | 
					            s = sections[i];
 | 
				
			||||||
            if (s->reloc && s != got)
 | 
					            if (s->reloc && s != got)
 | 
				
			||||||
                relocate_section(s);
 | 
					                relocate_section(s);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* get entry point address */
 | 
				
			||||||
 | 
					        ehdr.e_entry = get_elf_sym_val("_start");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					
 | 
				
			||||||
 | 
					    sort_syms(symtab_section);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* align to 4 */
 | 
					    /* align to 4 */
 | 
				
			||||||
    file_offset = (file_offset + 3) & -4;
 | 
					    file_offset = (file_offset + 3) & -4;
 | 
				
			||||||
| 
						 | 
					@ -7004,7 +7118,6 @@ int tcc_output_file(TCCState *s1, const char *filename, int file_type)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    ehdr.e_machine = EM_386;
 | 
					    ehdr.e_machine = EM_386;
 | 
				
			||||||
    ehdr.e_version = EV_CURRENT;
 | 
					    ehdr.e_version = EV_CURRENT;
 | 
				
			||||||
    ehdr.e_entry = 0; /* XXX: patch it */
 | 
					 | 
				
			||||||
    ehdr.e_shoff = file_offset;
 | 
					    ehdr.e_shoff = file_offset;
 | 
				
			||||||
    ehdr.e_ehsize = sizeof(Elf32_Ehdr);
 | 
					    ehdr.e_ehsize = sizeof(Elf32_Ehdr);
 | 
				
			||||||
    ehdr.e_shentsize = sizeof(Elf32_Shdr);
 | 
					    ehdr.e_shentsize = sizeof(Elf32_Shdr);
 | 
				
			||||||
| 
						 | 
					@ -7076,22 +7189,21 @@ typedef struct SectionMergeInfo {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* load an object file and merge it with current files */
 | 
					/* load an object file and merge it with current files */
 | 
				
			||||||
/* XXX: handle correctly stab (debug) info */
 | 
					/* XXX: handle correctly stab (debug) info */
 | 
				
			||||||
int tcc_load_object(TCCState *s1, const char *filename)
 | 
					static int tcc_load_object_file(TCCState *s1, 
 | 
				
			||||||
 | 
					                                const char *filename, 
 | 
				
			||||||
 | 
					                                FILE *f, unsigned long file_offset)
 | 
				
			||||||
{ 
 | 
					{ 
 | 
				
			||||||
    Elf32_Ehdr ehdr;
 | 
					    Elf32_Ehdr ehdr;
 | 
				
			||||||
    FILE *f;
 | 
					 | 
				
			||||||
    Elf32_Shdr *shdr, *sh;
 | 
					    Elf32_Shdr *shdr, *sh;
 | 
				
			||||||
    int size, i, j, offset, offsetl, offseti;
 | 
					    int size, i, j, offset, offseti, nb_syms, sym_index;
 | 
				
			||||||
    unsigned char *strsec;
 | 
					    unsigned char *strsec, *strtab;
 | 
				
			||||||
    char *sh_name;
 | 
					    int *old_to_new_syms;
 | 
				
			||||||
 | 
					    char *sh_name, *name;
 | 
				
			||||||
    SectionMergeInfo *sm_table, *sm;
 | 
					    SectionMergeInfo *sm_table, *sm;
 | 
				
			||||||
    Elf32_Sym *sym;
 | 
					    Elf32_Sym *sym, *symtab;
 | 
				
			||||||
    Elf32_Rel *rel;
 | 
					    Elf32_Rel *rel;
 | 
				
			||||||
    Section *s, *sl;
 | 
					    Section *s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    f = fopen(filename, "r");
 | 
					 | 
				
			||||||
    if (!f)
 | 
					 | 
				
			||||||
        error("could not open '%s'", filename);
 | 
					 | 
				
			||||||
    if (fread(&ehdr, 1, sizeof(ehdr), f) != sizeof(ehdr))
 | 
					    if (fread(&ehdr, 1, sizeof(ehdr), f) != sizeof(ehdr))
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    if (ehdr.e_ident[0] != ELFMAG0 ||
 | 
					    if (ehdr.e_ident[0] != ELFMAG0 ||
 | 
				
			||||||
| 
						 | 
					@ -7113,7 +7225,7 @@ int tcc_load_object(TCCState *s1, const char *filename)
 | 
				
			||||||
    shdr = malloc(size);
 | 
					    shdr = malloc(size);
 | 
				
			||||||
    if (!shdr)
 | 
					    if (!shdr)
 | 
				
			||||||
        error("memory full");
 | 
					        error("memory full");
 | 
				
			||||||
    fseek(f, ehdr.e_shoff, SEEK_SET);
 | 
					    fseek(f, file_offset + ehdr.e_shoff, SEEK_SET);
 | 
				
			||||||
    if (fread(shdr, 1, size, f) != size)
 | 
					    if (fread(shdr, 1, size, f) != size)
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7127,9 +7239,36 @@ int tcc_load_object(TCCState *s1, const char *filename)
 | 
				
			||||||
    strsec = malloc(sh->sh_size);
 | 
					    strsec = malloc(sh->sh_size);
 | 
				
			||||||
    if (!strsec)
 | 
					    if (!strsec)
 | 
				
			||||||
        error("memory full");
 | 
					        error("memory full");
 | 
				
			||||||
    fseek(f, sh->sh_offset, SEEK_SET);
 | 
					    fseek(f, file_offset + sh->sh_offset, SEEK_SET);
 | 
				
			||||||
    fread(strsec, 1, sh->sh_size, f);
 | 
					    fread(strsec, 1, sh->sh_size, f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* load symtab and strtab */
 | 
				
			||||||
 | 
					    symtab = NULL;
 | 
				
			||||||
 | 
					    strtab = NULL;
 | 
				
			||||||
 | 
					    nb_syms = 0;
 | 
				
			||||||
 | 
					    for(i = 1; i < ehdr.e_shnum; i++) {
 | 
				
			||||||
 | 
					        sh = &shdr[i];
 | 
				
			||||||
 | 
					        if (sh->sh_type == SHT_SYMTAB) {
 | 
				
			||||||
 | 
					            if (symtab)
 | 
				
			||||||
 | 
					                error("object must contain only one symtab");
 | 
				
			||||||
 | 
					            nb_syms = sh->sh_size / sizeof(Elf32_Sym);
 | 
				
			||||||
 | 
					            symtab = malloc(sh->sh_size);
 | 
				
			||||||
 | 
					            if (!symtab)
 | 
				
			||||||
 | 
					                error("memory full");
 | 
				
			||||||
 | 
					            fseek(f, file_offset + sh->sh_offset, SEEK_SET);
 | 
				
			||||||
 | 
					            fread(symtab, 1, sh->sh_size, f);
 | 
				
			||||||
 | 
					            sm_table[i].s = symtab_section;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* now load strtab */
 | 
				
			||||||
 | 
					            sh = &shdr[sh->sh_link];
 | 
				
			||||||
 | 
					            strtab = malloc(sh->sh_size);
 | 
				
			||||||
 | 
					            if (!strtab)
 | 
				
			||||||
 | 
					                error("memory full");
 | 
				
			||||||
 | 
					            fseek(f, file_offset + sh->sh_offset, SEEK_SET);
 | 
				
			||||||
 | 
					            fread(strtab, 1, sh->sh_size, f);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
    /* now examine each section and try to merge its content with the
 | 
					    /* now examine each section and try to merge its content with the
 | 
				
			||||||
       ones in memory */
 | 
					       ones in memory */
 | 
				
			||||||
    for(i = 1; i < ehdr.e_shnum; i++) {
 | 
					    for(i = 1; i < ehdr.e_shnum; i++) {
 | 
				
			||||||
| 
						 | 
					@ -7138,11 +7277,8 @@ int tcc_load_object(TCCState *s1, const char *filename)
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
        sh = &shdr[i];
 | 
					        sh = &shdr[i];
 | 
				
			||||||
        sh_name = strsec + sh->sh_name;
 | 
					        sh_name = strsec + sh->sh_name;
 | 
				
			||||||
        printf("%d: sh_name=%s\n", i, sh_name);
 | 
					 | 
				
			||||||
        /* ignore sections types we do not handle */
 | 
					        /* ignore sections types we do not handle */
 | 
				
			||||||
        if (sh->sh_type != SHT_PROGBITS &&
 | 
					        if (sh->sh_type != SHT_PROGBITS &&
 | 
				
			||||||
            sh->sh_type != SHT_SYMTAB &&
 | 
					 | 
				
			||||||
            sh->sh_type != SHT_STRTAB &&
 | 
					 | 
				
			||||||
            sh->sh_type != SHT_REL && 
 | 
					            sh->sh_type != SHT_REL && 
 | 
				
			||||||
            sh->sh_type != SHT_NOBITS)
 | 
					            sh->sh_type != SHT_NOBITS)
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
| 
						 | 
					@ -7164,11 +7300,6 @@ int tcc_load_object(TCCState *s1, const char *filename)
 | 
				
			||||||
    found:
 | 
					    found:
 | 
				
			||||||
        if (sh->sh_type != s->sh_type)
 | 
					        if (sh->sh_type != s->sh_type)
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
        if (sh->sh_type == SHT_SYMTAB) {
 | 
					 | 
				
			||||||
            /* if symbol, suppress first dummy entry */
 | 
					 | 
				
			||||||
            sh->sh_size -= sizeof(Elf32_Sym);
 | 
					 | 
				
			||||||
            sh->sh_offset += sizeof(Elf32_Sym);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* align start of section */
 | 
					        /* align start of section */
 | 
				
			||||||
        offset = s->data_ptr - s->data;
 | 
					        offset = s->data_ptr - s->data;
 | 
				
			||||||
| 
						 | 
					@ -7182,7 +7313,7 @@ int tcc_load_object(TCCState *s1, const char *filename)
 | 
				
			||||||
        /* concatenate sections */
 | 
					        /* concatenate sections */
 | 
				
			||||||
        size = sh->sh_size;
 | 
					        size = sh->sh_size;
 | 
				
			||||||
        if (sh->sh_type != SHT_NOBITS) {
 | 
					        if (sh->sh_type != SHT_NOBITS) {
 | 
				
			||||||
            fseek(f, sh->sh_offset, SEEK_SET);
 | 
					            fseek(f, file_offset + sh->sh_offset, SEEK_SET);
 | 
				
			||||||
            fread(s->data_ptr, 1, size, f);
 | 
					            fread(s->data_ptr, 1, size, f);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        s->data_ptr += size;
 | 
					        s->data_ptr += size;
 | 
				
			||||||
| 
						 | 
					@ -7205,7 +7336,32 @@ int tcc_load_object(TCCState *s1, const char *filename)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* third pass to patch symbol and relocation entries */
 | 
					    /* resolve symbols */
 | 
				
			||||||
 | 
					    old_to_new_syms = malloc(nb_syms * sizeof(int));
 | 
				
			||||||
 | 
					    if (!old_to_new_syms)
 | 
				
			||||||
 | 
					        error("memory full");
 | 
				
			||||||
 | 
					    memset(old_to_new_syms, 0, nb_syms * sizeof(int));
 | 
				
			||||||
 | 
					    sym = symtab + 1;
 | 
				
			||||||
 | 
					    for(i = 1; i < nb_syms; i++, sym++) {
 | 
				
			||||||
 | 
					        if (sym->st_shndx != SHN_UNDEF &&
 | 
				
			||||||
 | 
					            sym->st_shndx < SHN_LORESERVE) {
 | 
				
			||||||
 | 
					            sm = &sm_table[sym->st_shndx];
 | 
				
			||||||
 | 
					            /* if no corresponding section added, no need to add symbol */
 | 
				
			||||||
 | 
					            if (!sm->s)
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            /* convert section number */
 | 
				
			||||||
 | 
					            sym->st_shndx = sm->s->sh_num;
 | 
				
			||||||
 | 
					            /* offset value */
 | 
				
			||||||
 | 
					            sym->st_value += sm->offset;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /* add symbol */
 | 
				
			||||||
 | 
					        name = strtab + sym->st_name;
 | 
				
			||||||
 | 
					        sym_index = add_elf_sym(sym->st_value, sym->st_size, 
 | 
				
			||||||
 | 
					                                sym->st_info, sym->st_shndx, name);
 | 
				
			||||||
 | 
					        old_to_new_syms[i] = sym_index;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* third pass to patch relocation entries */
 | 
				
			||||||
    for(i = 1; i < ehdr.e_shnum; i++) {
 | 
					    for(i = 1; i < ehdr.e_shnum; i++) {
 | 
				
			||||||
        s = sm_table[i].s;
 | 
					        s = sm_table[i].s;
 | 
				
			||||||
        if (!s)
 | 
					        if (!s)
 | 
				
			||||||
| 
						 | 
					@ -7213,59 +7369,25 @@ int tcc_load_object(TCCState *s1, const char *filename)
 | 
				
			||||||
        sh = &shdr[i];
 | 
					        sh = &shdr[i];
 | 
				
			||||||
        offset = sm_table[i].offset;
 | 
					        offset = sm_table[i].offset;
 | 
				
			||||||
        switch(s->sh_type) {
 | 
					        switch(s->sh_type) {
 | 
				
			||||||
        case SHT_SYMTAB:
 | 
					 | 
				
			||||||
            /* take strtab offset information */
 | 
					 | 
				
			||||||
            sl = sm_table[sh->sh_link].s;
 | 
					 | 
				
			||||||
            offsetl = sm_table[sh->sh_link].offset;
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            for(sym = (Elf32_Sym *)(s->data + offset);
 | 
					 | 
				
			||||||
                sym < (Elf32_Sym *)s->data_ptr;
 | 
					 | 
				
			||||||
                sym++) {
 | 
					 | 
				
			||||||
                /* offset name */
 | 
					 | 
				
			||||||
                if (sym->st_name != 0)
 | 
					 | 
				
			||||||
                    sym->st_name += offsetl;
 | 
					 | 
				
			||||||
                /* add to internal hash table */
 | 
					 | 
				
			||||||
                if (s->hash) {
 | 
					 | 
				
			||||||
                    update_hash_elf_sym(s->hash, sym - (Elf32_Sym *)s->data,
 | 
					 | 
				
			||||||
                                        sym->st_info, sl->data + sym->st_name);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                /* no need to patch */
 | 
					 | 
				
			||||||
                if (sym->st_shndx == SHN_UNDEF ||
 | 
					 | 
				
			||||||
                    sym->st_shndx >= SHN_LORESERVE)
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                /* transform section number */
 | 
					 | 
				
			||||||
                sm = &sm_table[sym->st_shndx];
 | 
					 | 
				
			||||||
                if (sm->s) {
 | 
					 | 
				
			||||||
                    sym->st_shndx = sm->s->sh_num;
 | 
					 | 
				
			||||||
                    /* offset value */
 | 
					 | 
				
			||||||
                    sym->st_value += sm->offset;
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    /* if the section was suppressed, we put a dummy symbol */
 | 
					 | 
				
			||||||
                    /* XXX: suppress it ? */
 | 
					 | 
				
			||||||
                    sym->st_value = 0;
 | 
					 | 
				
			||||||
                    sym->st_shndx = SHN_ABS;
 | 
					 | 
				
			||||||
                    sym->st_info = 0;
 | 
					 | 
				
			||||||
                    sym->st_name = 0;
 | 
					 | 
				
			||||||
                    printf("warning: invalid symbol %d\n", 
 | 
					 | 
				
			||||||
                           sym - (Elf32_Sym *)(s->data + offset) + 1);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        case SHT_REL:
 | 
					        case SHT_REL:
 | 
				
			||||||
            /* take symbol offset information */
 | 
					 | 
				
			||||||
            /* minus one because we deleted the first symbol */
 | 
					 | 
				
			||||||
            offsetl = (sm_table[sh->sh_link].offset / sizeof(Elf32_Sym)) - 1;
 | 
					 | 
				
			||||||
            /* take relocation offset information */
 | 
					            /* take relocation offset information */
 | 
				
			||||||
            offseti = sm_table[sh->sh_info].offset;
 | 
					            offseti = sm_table[sh->sh_info].offset;
 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            for(rel = (Elf32_Rel *)(s->data + offset);
 | 
					            for(rel = (Elf32_Rel *)(s->data + offset);
 | 
				
			||||||
                rel < (Elf32_Rel *)s->data_ptr;
 | 
					                rel < (Elf32_Rel *)s->data_ptr;
 | 
				
			||||||
                rel++) {
 | 
					                rel++) {
 | 
				
			||||||
                int type, sym_index;
 | 
					                int type;
 | 
				
			||||||
                /* offset symbol index */
 | 
					                unsigned sym_index;
 | 
				
			||||||
 | 
					                /* convert symbol index */
 | 
				
			||||||
                type = ELF32_R_TYPE(rel->r_info);
 | 
					                type = ELF32_R_TYPE(rel->r_info);
 | 
				
			||||||
                sym_index = ELF32_R_SYM(rel->r_info);
 | 
					                sym_index = ELF32_R_SYM(rel->r_info);
 | 
				
			||||||
                sym_index += offsetl;
 | 
					                /* NOTE: only one symtab assumed */
 | 
				
			||||||
 | 
					                if (sym_index >= nb_syms)
 | 
				
			||||||
 | 
					                    goto invalid_reloc;
 | 
				
			||||||
 | 
					                sym_index = old_to_new_syms[sym_index];
 | 
				
			||||||
 | 
					                if (!sym_index) {
 | 
				
			||||||
 | 
					                invalid_reloc:
 | 
				
			||||||
 | 
					                    error("Invalid relocation entry");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                rel->r_info = ELF32_R_INFO(sym_index, type);
 | 
					                rel->r_info = ELF32_R_INFO(sym_index, type);
 | 
				
			||||||
                /* offset the relocation offset */
 | 
					                /* offset the relocation offset */
 | 
				
			||||||
                rel->r_offset += offseti;
 | 
					                rel->r_offset += offseti;
 | 
				
			||||||
| 
						 | 
					@ -7275,12 +7397,93 @@ int tcc_load_object(TCCState *s1, const char *filename)
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    free(symtab);
 | 
				
			||||||
 | 
					    free(strtab);
 | 
				
			||||||
 | 
					    free(old_to_new_syms);
 | 
				
			||||||
    free(sm_table);
 | 
					    free(sm_table);
 | 
				
			||||||
    free(shdr);
 | 
					    free(shdr);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int tcc_load_object(TCCState *s1, const char *filename)
 | 
				
			||||||
 | 
					{ 
 | 
				
			||||||
 | 
					    FILE *f;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    f = fopen(filename, "r");
 | 
				
			||||||
 | 
					    if (!f)
 | 
				
			||||||
 | 
					        error("could not open '%s'", filename);
 | 
				
			||||||
 | 
					    ret = tcc_load_object_file(s1, filename, f, 0);
 | 
				
			||||||
 | 
					    fclose(f);
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ARMAG  "!<arch>\012"	/* For COFF and a.out archives */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct ArchiveHeader {
 | 
				
			||||||
 | 
					    char ar_name[16];		/* name of this member */
 | 
				
			||||||
 | 
					    char ar_date[12];		/* file mtime */
 | 
				
			||||||
 | 
					    char ar_uid[6];		/* owner uid; printed as decimal */
 | 
				
			||||||
 | 
					    char ar_gid[6];		/* owner gid; printed as decimal */
 | 
				
			||||||
 | 
					    char ar_mode[8];		/* file mode, printed as octal   */
 | 
				
			||||||
 | 
					    char ar_size[10];		/* file size, printed as decimal */
 | 
				
			||||||
 | 
					    char ar_fmag[2];		/* should contain ARFMAG */
 | 
				
			||||||
 | 
					} ArchiveHeader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* load a '.a' file */
 | 
				
			||||||
 | 
					int tcc_load_archive(TCCState *s1, const char *filename)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ArchiveHeader hdr;
 | 
				
			||||||
 | 
					    char magic[8];
 | 
				
			||||||
 | 
					    char ar_size[11];
 | 
				
			||||||
 | 
					    char ar_name[17];
 | 
				
			||||||
 | 
					    int size, len, i;
 | 
				
			||||||
 | 
					    FILE *f;
 | 
				
			||||||
 | 
					    unsigned long file_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    f = fopen(filename, "r");
 | 
				
			||||||
 | 
					    if (!f)
 | 
				
			||||||
 | 
					        error("could not open '%s'", filename);
 | 
				
			||||||
 | 
					    len = fread(magic, 1, sizeof(magic), f);
 | 
				
			||||||
 | 
					    if (len != sizeof(magic) || 
 | 
				
			||||||
 | 
					        memcmp(magic, ARMAG, sizeof(magic)) != 0)
 | 
				
			||||||
 | 
					        error("invalid archive magic");
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    for(;;) {
 | 
				
			||||||
 | 
					        len = fread(&hdr, 1, sizeof(hdr), f);
 | 
				
			||||||
 | 
					        if (len == 0)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        if (len != sizeof(hdr))
 | 
				
			||||||
 | 
					            error("invalid archive");
 | 
				
			||||||
 | 
					        memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size));
 | 
				
			||||||
 | 
					        ar_size[sizeof(hdr.ar_size)] = '\0';
 | 
				
			||||||
 | 
					        size = strtol(ar_size, NULL, 0);
 | 
				
			||||||
 | 
					        memcpy(ar_name, hdr.ar_name, sizeof(hdr.ar_name));
 | 
				
			||||||
 | 
					        for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) {
 | 
				
			||||||
 | 
					            if (ar_name[i] != ' ')
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ar_name[i + 1] = '\0';
 | 
				
			||||||
 | 
					        //        printf("name='%s' size=%d %s\n", ar_name, size, ar_size);
 | 
				
			||||||
 | 
					        file_offset = ftell(f);
 | 
				
			||||||
 | 
					        if (!strcmp(ar_name, "/") ||
 | 
				
			||||||
 | 
					            !strcmp(ar_name, "//") ||
 | 
				
			||||||
 | 
					            !strcmp(ar_name, "__.SYMDEF") ||
 | 
				
			||||||
 | 
					            !strcmp(ar_name, "__.SYMDEF/") ||
 | 
				
			||||||
 | 
					            !strcmp(ar_name, "ARFILENAMES/")) {
 | 
				
			||||||
 | 
					            /* skip symbol table or archive names */
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            tcc_load_object_file(s1, filename, f, file_offset);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /* align to even */
 | 
				
			||||||
 | 
					        size = (size + 1) & ~1;
 | 
				
			||||||
 | 
					        fseek(f, file_offset + size, SEEK_SET);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    fclose(f);
 | 
					    fclose(f);
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* print the position in the source file of PC value 'pc' by reading
 | 
					/* print the position in the source file of PC value 'pc' by reading
 | 
				
			||||||
   the stabs debug information */
 | 
					   the stabs debug information */
 | 
				
			||||||
static void rt_printline(unsigned long wanted_pc)
 | 
					static void rt_printline(unsigned long wanted_pc)
 | 
				
			||||||
| 
						 | 
					@ -7427,43 +7630,13 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void *resolve_sym(const char *sym)
 | 
					/* launch the compiled program with the given arguments */
 | 
				
			||||||
{
 | 
					int tcc_run(TCCState *s1, int argc, char **argv)
 | 
				
			||||||
#ifdef CONFIG_TCC_BCHECK
 | 
					 | 
				
			||||||
    if (do_bounds_check) {
 | 
					 | 
				
			||||||
        void *ptr;
 | 
					 | 
				
			||||||
        ptr = bound_resolve_sym(sym);
 | 
					 | 
				
			||||||
        if (ptr)
 | 
					 | 
				
			||||||
            return ptr;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    return dlsym(NULL, sym);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void resolve_extern_syms(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    unsigned long addr;
 | 
					 | 
				
			||||||
    Elf32_Sym *sym;
 | 
					 | 
				
			||||||
    const char *name;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    for(sym = (Elf32_Sym *)symtab_section->data + 1; 
 | 
					 | 
				
			||||||
        sym < (Elf32_Sym *)symtab_section->data_ptr;
 | 
					 | 
				
			||||||
        sym++) {
 | 
					 | 
				
			||||||
        if (sym->st_shndx == SHN_UNDEF) {
 | 
					 | 
				
			||||||
            name = symtab_section->link->data + sym->st_name;
 | 
					 | 
				
			||||||
            addr = (unsigned long)resolve_sym(name);
 | 
					 | 
				
			||||||
            if (!addr)
 | 
					 | 
				
			||||||
                error("unresolved external reference '%s'", name);
 | 
					 | 
				
			||||||
            sym->st_value = addr;
 | 
					 | 
				
			||||||
            sym->st_shndx = SHN_ABS;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* relocate all the code and data */
 | 
					 | 
				
			||||||
static void relocate_program(void)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Section *s;
 | 
					    Section *s;
 | 
				
			||||||
 | 
					    int (*prog_main)(int, char **);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relocate_common_syms();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* compute relocation address : section are relocated in place */
 | 
					    /* compute relocation address : section are relocated in place */
 | 
				
			||||||
    for(s = first_section; s != NULL; s = s->next) {
 | 
					    for(s = first_section; s != NULL; s = s->next) {
 | 
				
			||||||
| 
						 | 
					@ -7471,27 +7644,15 @@ static void relocate_program(void)
 | 
				
			||||||
            s->sh_addr = (unsigned long)s->data;
 | 
					            s->sh_addr = (unsigned long)s->data;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    relocate_syms(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* relocate each section */
 | 
					    /* relocate each section */
 | 
				
			||||||
    for(s = first_section; s != NULL; s = s->next) {
 | 
					    for(s = first_section; s != NULL; s = s->next) {
 | 
				
			||||||
        if ((s->sh_flags & SHF_ALLOC) && s->reloc)
 | 
					        if ((s->sh_flags & SHF_ALLOC) && s->reloc)
 | 
				
			||||||
            relocate_section(s);
 | 
					            relocate_section(s);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* launch the compiled program with the given arguments */
 | 
					    prog_main = (void *)get_elf_sym_val("main");
 | 
				
			||||||
int tcc_run(TCCState *s1, int argc, char **argv)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int (*prog_main)(int, char **);
 | 
					 | 
				
			||||||
    int sym_index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    resolve_extern_syms();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    relocate_program();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sym_index = find_elf_sym(symtab_section, "main");
 | 
					 | 
				
			||||||
    if (!sym_index)
 | 
					 | 
				
			||||||
        error("main() not defined");
 | 
					 | 
				
			||||||
    prog_main = (void *)get_sym_val(sym_index);
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (do_debug) {
 | 
					    if (do_debug) {
 | 
				
			||||||
#ifdef WIN32
 | 
					#ifdef WIN32
 | 
				
			||||||
| 
						 | 
					@ -7611,10 +7772,16 @@ void tcc_add_file(TCCState *s, const char *filename)
 | 
				
			||||||
        ext = '\0';
 | 
					        ext = '\0';
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        ext = p[1];
 | 
					        ext = p[1];
 | 
				
			||||||
    if (ext == 'o') {
 | 
					    switch(ext) {
 | 
				
			||||||
 | 
					    case 'o':
 | 
				
			||||||
        tcc_load_object(s, filename);
 | 
					        tcc_load_object(s, filename);
 | 
				
			||||||
    } else {
 | 
					        break;
 | 
				
			||||||
 | 
					    case 'a':
 | 
				
			||||||
 | 
					        tcc_load_archive(s, filename);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
        tcc_compile_file(s, filename);
 | 
					        tcc_compile_file(s, filename);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7627,7 +7794,6 @@ void help(void)
 | 
				
			||||||
           "\n"
 | 
					           "\n"
 | 
				
			||||||
           "General options:\n"
 | 
					           "General options:\n"
 | 
				
			||||||
           "  -c          compile only - generate an object file\n"
 | 
					           "  -c          compile only - generate an object file\n"
 | 
				
			||||||
           "  -i infile   compile infile\n"
 | 
					 | 
				
			||||||
           "  -o outfile  set output filename (NOT WORKING YET)\n"
 | 
					           "  -o outfile  set output filename (NOT WORKING YET)\n"
 | 
				
			||||||
           "  -bench      output compilation statistics\n"
 | 
					           "  -bench      output compilation statistics\n"
 | 
				
			||||||
           "  --          allows multiples input files if no -o option given. Also\n" 
 | 
					           "  --          allows multiples input files if no -o option given. Also\n" 
 | 
				
			||||||
| 
						 | 
					@ -7673,6 +7839,8 @@ int main(int argc, char **argv)
 | 
				
			||||||
        if (r[1] == '-') {
 | 
					        if (r[1] == '-') {
 | 
				
			||||||
            /* '--' enables multiple files input */
 | 
					            /* '--' enables multiple files input */
 | 
				
			||||||
            multiple_files = 1;
 | 
					            multiple_files = 1;
 | 
				
			||||||
 | 
					        } else if (r[1] == 'h' || r[1] == '?') {
 | 
				
			||||||
 | 
					            goto show_help;
 | 
				
			||||||
        } else if (r[1] == 'I') {
 | 
					        } else if (r[1] == 'I') {
 | 
				
			||||||
            if (tcc_add_include_path(s, r + 2) < 0)
 | 
					            if (tcc_add_include_path(s, r + 2) < 0)
 | 
				
			||||||
                error("too many include paths");
 | 
					                error("too many include paths");
 | 
				
			||||||
| 
						 | 
					@ -7744,6 +7912,13 @@ int main(int argc, char **argv)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* add libc crt1/crti objects */
 | 
				
			||||||
 | 
					    if (outfile && file_type != TCC_FILE_OBJ) {
 | 
				
			||||||
 | 
					        if (file_type != TCC_FILE_DLL)
 | 
				
			||||||
 | 
					            tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o");
 | 
				
			||||||
 | 
					        tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tcc_add_file(s, argv[optind]);
 | 
					    tcc_add_file(s, argv[optind]);
 | 
				
			||||||
    if (multiple_files) {
 | 
					    if (multiple_files) {
 | 
				
			||||||
        while ((optind + 1) < argc) {
 | 
					        while ((optind + 1) < argc) {
 | 
				
			||||||
| 
						 | 
					@ -7758,6 +7933,11 @@ int main(int argc, char **argv)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* add libc crtn object */
 | 
				
			||||||
 | 
					    if (outfile && file_type != TCC_FILE_OBJ) {
 | 
				
			||||||
 | 
					        tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crtn.o");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (do_bench) {
 | 
					    if (do_bench) {
 | 
				
			||||||
        printf("total: %d idents, %d lines, %d bytes\n", 
 | 
					        printf("total: %d idents, %d lines, %d bytes\n", 
 | 
				
			||||||
               tok_ident - TOK_IDENT, total_lines, total_bytes);
 | 
					               tok_ident - TOK_IDENT, total_lines, total_bytes);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue