📄 tccelf.c
字号:
put_dt(dynamic, DT_STRSZ, dynstr->data_offset); put_dt(dynamic, DT_SYMENT, sizeof(Elf32_Sym)); put_dt(dynamic, DT_REL, rel_addr); put_dt(dynamic, DT_RELSZ, rel_size); put_dt(dynamic, DT_RELENT, sizeof(Elf32_Rel)); put_dt(dynamic, DT_NULL, 0); } ehdr.e_phentsize = sizeof(Elf32_Phdr); ehdr.e_phnum = phnum; ehdr.e_phoff = sizeof(Elf32_Ehdr); } /* all other sections come after */ for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) continue; section_order[sh_order_index++] = i; file_offset = (file_offset + s->sh_addralign - 1) & ~(s->sh_addralign - 1); s->sh_offset = file_offset; if (s->sh_type != SHT_NOBITS) file_offset += s->sh_size; } /* if building executable or DLL, then relocate each section except the GOT which is already relocated */ if (file_type != TCC_OUTPUT_OBJ) { relocate_syms(s1, 0); if (s1->nb_errors != 0) { fail: ret = -1; goto the_end; } /* relocate sections */ /* XXX: ignore sections with allocated relocations ? */ for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; if (s->reloc && s != s1->got) relocate_section(s1, s); } /* relocate relocation entries if the relocation tables are allocated in the executable */ for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; if ((s->sh_flags & SHF_ALLOC) && s->sh_type == SHT_REL) { relocate_rel(s1, s); } } /* get entry point address */ if (file_type == TCC_OUTPUT_EXE) ehdr.e_entry = (unsigned long)tcc_get_symbol_err(s1, "_start"); else ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ } /* write elf file */ if (file_type == TCC_OUTPUT_OBJ) mode = 0666; else mode = 0777; fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); if (fd < 0) { error_noabort("could not write '%s'", filename); goto fail; } f = fdopen(fd, "wb");#ifdef TCC_TARGET_COFF if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) { tcc_output_coff(s1, f); } else#endif if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { sort_syms(s1, symtab_section); /* align to 4 */ file_offset = (file_offset + 3) & -4; /* fill header */ ehdr.e_ident[0] = ELFMAG0; ehdr.e_ident[1] = ELFMAG1; ehdr.e_ident[2] = ELFMAG2; ehdr.e_ident[3] = ELFMAG3; ehdr.e_ident[4] = ELFCLASS32; ehdr.e_ident[5] = ELFDATA2LSB; ehdr.e_ident[6] = EV_CURRENT;#ifdef __FreeBSD__ ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;#endif#ifdef TCC_TARGET_ARM ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM;#endif switch(file_type) { default: case TCC_OUTPUT_EXE: ehdr.e_type = ET_EXEC; break; case TCC_OUTPUT_DLL: ehdr.e_type = ET_DYN; break; case TCC_OUTPUT_OBJ: ehdr.e_type = ET_REL; break; } ehdr.e_machine = EM_TCC_TARGET; ehdr.e_version = EV_CURRENT; ehdr.e_shoff = file_offset; ehdr.e_ehsize = sizeof(Elf32_Ehdr); ehdr.e_shentsize = sizeof(Elf32_Shdr); ehdr.e_shnum = shnum; ehdr.e_shstrndx = shnum - 1; fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f); fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f); offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr); for(i=1;i<s1->nb_sections;i++) { s = s1->sections[section_order[i]]; if (s->sh_type != SHT_NOBITS) { while (offset < s->sh_offset) { fputc(0, f); offset++; } size = s->sh_size; fwrite(s->data, 1, size, f); offset += size; } } /* output section headers */ while (offset < ehdr.e_shoff) { fputc(0, f); offset++; } for(i=0;i<s1->nb_sections;i++) { sh = &shdr; memset(sh, 0, sizeof(Elf32_Shdr)); s = s1->sections[i]; if (s) { sh->sh_name = s->sh_name; sh->sh_type = s->sh_type; sh->sh_flags = s->sh_flags; sh->sh_entsize = s->sh_entsize; sh->sh_info = s->sh_info; if (s->link) sh->sh_link = s->link->sh_num; sh->sh_addralign = s->sh_addralign; sh->sh_addr = s->sh_addr; sh->sh_offset = s->sh_offset; sh->sh_size = s->sh_size; } fwrite(sh, 1, sizeof(Elf32_Shdr), f); } } else { tcc_output_binary(s1, f, section_order); } fclose(f); ret = 0; the_end: tcc_free(s1->symtab_to_dynsym); tcc_free(section_order); tcc_free(phdr); tcc_free(s1->got_offsets); return ret;}static void *load_data(int fd, unsigned long file_offset, unsigned long size){ void *data; data = tcc_malloc(size); lseek(fd, file_offset, SEEK_SET); read(fd, data, size); return data;}typedef struct SectionMergeInfo { Section *s; /* corresponding existing section */ unsigned long offset; /* offset of the new section in the existing section */ uint8_t new_section; /* true if section 's' was added */ uint8_t link_once; /* true if link once section */} SectionMergeInfo;/* load an object file and merge it with current files *//* XXX: handle correctly stab (debug) info */static int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset){ Elf32_Ehdr ehdr; Elf32_Shdr *shdr, *sh; int size, i, j, offset, offseti, nb_syms, sym_index, ret; unsigned char *strsec, *strtab; int *old_to_new_syms; char *sh_name, *name; SectionMergeInfo *sm_table, *sm; Elf32_Sym *sym, *symtab; Elf32_Rel *rel, *rel_end; Section *s; if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) goto fail1; if (ehdr.e_ident[0] != ELFMAG0 || ehdr.e_ident[1] != ELFMAG1 || ehdr.e_ident[2] != ELFMAG2 || ehdr.e_ident[3] != ELFMAG3) goto fail1; /* test if object file */ if (ehdr.e_type != ET_REL) goto fail1; /* test CPU specific stuff */ if (ehdr.e_ident[5] != ELFDATA2LSB || ehdr.e_machine != EM_TCC_TARGET) { fail1: error_noabort("invalid object file"); return -1; } /* read sections */ shdr = load_data(fd, file_offset + ehdr.e_shoff, sizeof(Elf32_Shdr) * ehdr.e_shnum); sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum); /* load section names */ sh = &shdr[ehdr.e_shstrndx]; strsec = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); /* load symtab and strtab */ old_to_new_syms = NULL; 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_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]; off
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -