📄 tccelf.c
字号:
error_noabort("object must contain only one symtab"); fail: ret = -1; goto the_end; } nb_syms = sh->sh_size / sizeof(Elf32_Sym); symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); sm_table[i].s = symtab_section; /* now load strtab */ sh = &shdr[sh->sh_link]; strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); } } /* now examine each section and try to merge its content with the ones in memory */ for(i = 1; i < ehdr.e_shnum; i++) { /* no need to examine section name strtab */ if (i == ehdr.e_shstrndx) continue; sh = &shdr[i]; sh_name = strsec + sh->sh_name; /* ignore sections types we do not handle */ if (sh->sh_type != SHT_PROGBITS && sh->sh_type != SHT_REL && sh->sh_type != SHT_NOBITS) continue; if (sh->sh_addralign < 1) sh->sh_addralign = 1; /* find corresponding section, if any */ for(j = 1; j < s1->nb_sections;j++) { s = s1->sections[j]; if (!strcmp(s->name, sh_name)) { if (!strncmp(sh_name, ".gnu.linkonce", sizeof(".gnu.linkonce") - 1)) { /* if a 'linkonce' section is already present, we do not add it again. It is a little tricky as symbols can still be defined in it. */ sm_table[i].link_once = 1; goto next; } else { goto found; } } } /* not found: create new section */ s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags); /* take as much info as possible from the section. sh_link and sh_info will be updated later */ s->sh_addralign = sh->sh_addralign; s->sh_entsize = sh->sh_entsize; sm_table[i].new_section = 1; found: if (sh->sh_type != s->sh_type) { error_noabort("invalid section type"); goto fail; } /* align start of section */ offset = s->data_offset; size = sh->sh_addralign - 1; offset = (offset + size) & ~size; if (sh->sh_addralign > s->sh_addralign) s->sh_addralign = sh->sh_addralign; s->data_offset = offset; sm_table[i].offset = offset; sm_table[i].s = s; /* concatenate sections */ size = sh->sh_size; if (sh->sh_type != SHT_NOBITS) { unsigned char *ptr; lseek(fd, file_offset + sh->sh_offset, SEEK_SET); ptr = section_ptr_add(s, size); read(fd, ptr, size); } else { s->data_offset += size; } next: ; } /* second short pass to update sh_link and sh_info fields of new sections */ sm = sm_table; for(i = 1; i < ehdr.e_shnum; i++) { s = sm_table[i].s; if (!s || !sm_table[i].new_section) continue; sh = &shdr[i]; if (sh->sh_link > 0) s->link = sm_table[sh->sh_link].s; if (sh->sh_type == SHT_REL) { s->sh_info = sm_table[sh->sh_info].s->sh_num; /* update backward link */ s1->sections[s->sh_info]->reloc = s; } } /* resolve symbols */ old_to_new_syms = tcc_mallocz(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 (sm->link_once) { /* if a symbol is in a link once section, we use the already defined symbol. It is very important to get correct relocations */ if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { name = strtab + sym->st_name; sym_index = find_elf_sym(symtab_section, name); if (sym_index) old_to_new_syms[i] = sym_index; } continue; } /* 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(symtab_section, 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++) { s = sm_table[i].s; if (!s) continue; sh = &shdr[i]; offset = sm_table[i].offset; switch(s->sh_type) { case SHT_REL: /* take relocation offset information */ offseti = sm_table[sh->sh_info].offset; rel_end = (Elf32_Rel *)(s->data + s->data_offset); for(rel = (Elf32_Rel *)(s->data + offset); rel < rel_end; rel++) { int type; unsigned sym_index; /* convert symbol index */ type = ELF32_R_TYPE(rel->r_info); sym_index = ELF32_R_SYM(rel->r_info); /* 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_noabort("Invalid relocation entry"); goto fail; } rel->r_info = ELF32_R_INFO(sym_index, type); /* offset the relocation offset */ rel->r_offset += offseti; } break; default: break; } } ret = 0; the_end: tcc_free(symtab); tcc_free(strtab); tcc_free(old_to_new_syms); tcc_free(sm_table); tcc_free(strsec); tcc_free(shdr); 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;static int get_be32(const uint8_t *b){ return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24);}/* load only the objects which resolve undefined symbols */static int tcc_load_alacarte(TCCState *s1, int fd, int size){ int i, bound, nsyms, sym_index, off, ret; uint8_t *data; const char *ar_names, *p; const uint8_t *ar_index; Elf32_Sym *sym; data = tcc_malloc(size); if (read(fd, data, size) != size) goto fail; nsyms = get_be32(data); ar_index = data + 4; ar_names = ar_index + nsyms * 4; do { bound = 0; for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { sym_index = find_elf_sym(symtab_section, p); if(sym_index) { sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; if(sym->st_shndx == SHN_UNDEF) { off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader);#if 0 printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx);#endif ++bound; lseek(fd, off, SEEK_SET); if(tcc_load_object_file(s1, fd, off) < 0) { fail: ret = -1; goto the_end; } } } } } while(bound); ret = 0; the_end: tcc_free(data); return ret;}/* load a '.a' file */static int tcc_load_archive(TCCState *s1, int fd){ ArchiveHeader hdr; char ar_size[11]; char ar_name[17]; char magic[8]; int size, len, i; unsigned long file_offset; /* skip magic which was already checked */ read(fd, magic, sizeof(magic)); for(;;) { len = read(fd, &hdr, sizeof(hdr)); if (len == 0) break; if (len != sizeof(hdr)) { error_noabort("invalid archive"); return -1; } 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 = lseek(fd, 0, SEEK_CUR); /* align to even */ size = (size + 1) & ~1; if (!strcmp(ar_name, "/")) { /* coff symbol table : we handle it */ if(s1->alacarte_link) return tcc_load_alacarte(s1, fd, size); } else if (!strcmp(ar_name, "//") || !strcmp(ar_name, "__.SYMDEF") || !strcmp(ar_name, "__.SYMDEF/") || !strcmp(ar_name, "ARFILENAMES/")) { /* skip symbol table or archive names */ } else { if (tcc_load_object_file(s1, fd, file_offset) < 0) return -1; } lseek(fd, file_offset + size, SEEK_SET); } return 0;}/* load a DLL and all referenced DLLs. 'level = 0' means that the DLL is referenced by the user (so it should be added as DT_NEEDED in the generated ELF file) */static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level){ Elf32_Ehdr ehdr; Elf32_Shdr *shdr, *sh, *sh1; int i, nb_syms, nb_dts, sym_bind, ret; Elf32_Sym *sym, *dynsym; Elf32_Dyn *dt, *dynamic; unsigned char *dynstr; const char *name, *soname, *p; DLLReference *dllref; read(fd, &ehdr, sizeof(ehdr)); /* test CPU specific stuff */ if (ehdr.e_ident[5] != ELFDATA2LSB || ehdr.e_machine != EM_386) { error_noabort("bad architecture"); return -1; } /* read sections */ shdr = load_data(fd, ehdr.e_shoff, sizeof(Elf32_Shdr) * ehdr.e_shnum); /* load dynamic section and dynamic symbols */ nb_syms = 0; nb_dts = 0; dynamic = NULL; dynsym = NULL; /* avoid warning */ dynstr = NULL; /* avoid warning */ for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) { switch(sh->sh_type) { case SHT_DYNAMIC: nb_dts = sh->sh_size / sizeof(Elf32_Dyn); dynamic = load_data(fd, sh->sh_offset, sh->sh_size); break; case SHT_DYNSYM: nb_syms = sh->sh_size / sizeof(Elf32_Sym); dynsym = load_data(fd, sh->sh_offset, sh->sh_size); sh1 = &shdr[sh->sh_link]; dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size); break; default: break; } } /* compute the real library name */ soname = filename; p = strrchr(soname, '/'); if (p) soname = p + 1; for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { if (dt->d_tag == DT_SONAME) { soname = dynstr + dt->d_un.d_val; } } /* if the dll is already loaded, do not load it */ for(i = 0; i < s1->nb_loaded_dlls; i++) { dllref = s1->loaded_dlls[i]; if (!strcmp(soname, dllref->name)) { /* but update level if needed */ if (level < dllref->level) dllref->level = level; ret = 0; goto the_end; } } // printf("loading dll '%s'\n", soname); /* add the dll and its level */ dllref = tcc_malloc(sizeof(DLLReference) + strlen(soname)); dllref->level = level; strcpy(dllref->name, soname); dynarray_add((void ***)&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); /* add dynamic symbols in dynsym_section */ for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) { sym_bind = ELF32_ST_BIND(sym->st_info); if (sym_bind == STB_LOCAL) continue; name = dynstr + sym->st_name; add_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size, sym->st_info, sym->st_shndx, name); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -