📄 tccelf.c
字号:
else addr = ELF_START_ADDR; /* dynamic relocation table information, for .dynamic section */ rel_size = 0; rel_addr = 0; /* compute address after headers */ addr += (file_offset & (ELF_PAGE_SIZE - 1)); /* leave one program header for the program interpreter */ ph = &phdr[0]; if (interp) ph++; for(j = 0; j < 2; j++) { ph->p_type = PT_LOAD; if (j == 0) ph->p_flags = PF_R | PF_X; else ph->p_flags = PF_R | PF_W; ph->p_align = ELF_PAGE_SIZE; /* we do the following ordering: interp, symbol tables, relocations, progbits, nobits */ /* XXX: do faster and simpler sorting */ for(k = 0; k < 5; k++) { for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; /* compute if section should be included */ if (j == 0) { if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != SHF_ALLOC) continue; } else { if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != (SHF_ALLOC | SHF_WRITE)) continue; } if (s == interp) { if (k != 0) continue; } else if (s->sh_type == SHT_DYNSYM || s->sh_type == SHT_STRTAB || s->sh_type == SHT_HASH) { if (k != 1) continue; } else if (s->sh_type == SHT_REL) { if (k != 2) continue; } else if (s->sh_type == SHT_NOBITS) { if (k != 4) continue; } else { if (k != 3) continue; } section_order[sh_order_index++] = i; /* section matches: we align it and add its size */ tmp = file_offset; file_offset = (file_offset + s->sh_addralign - 1) & ~(s->sh_addralign - 1); s->sh_offset = file_offset; addr += file_offset - tmp; s->sh_addr = addr; /* update program header infos */ if (ph->p_offset == 0) { ph->p_offset = file_offset; ph->p_vaddr = addr; ph->p_paddr = ph->p_vaddr; } /* update dynamic relocation infos */ if (s->sh_type == SHT_REL) { if (rel_size == 0) rel_addr = addr; rel_size += s->sh_size; } addr += s->sh_size; if (s->sh_type != SHT_NOBITS) file_offset += s->sh_size; } } ph->p_filesz = file_offset - ph->p_offset; ph->p_memsz = addr - ph->p_vaddr; ph++; /* if in the middle of a page, we duplicate the page in memory so that one copy is RX and the other is RW */ if ((addr & (ELF_PAGE_SIZE - 1)) != 0) addr += ELF_PAGE_SIZE; } /* if interpreter, then add corresponing program header */ if (interp) { ph = &phdr[0]; ph->p_type = PT_INTERP; ph->p_offset = interp->sh_offset; ph->p_vaddr = interp->sh_addr; ph->p_paddr = ph->p_vaddr; ph->p_filesz = interp->sh_size; ph->p_memsz = interp->sh_size; ph->p_flags = PF_R; ph->p_align = interp->sh_addralign; } /* if dynamic section, then add corresponing program header */ if (dynamic) { Elf32_Sym *sym_end; ph = &phdr[phnum - 1]; ph->p_type = PT_DYNAMIC; ph->p_offset = dynamic->sh_offset; ph->p_vaddr = dynamic->sh_addr; ph->p_paddr = ph->p_vaddr; ph->p_filesz = dynamic->sh_size; ph->p_memsz = dynamic->sh_size; ph->p_flags = PF_R | PF_W; ph->p_align = dynamic->sh_addralign; /* put GOT dynamic section address */ put32(s1->got->data, dynamic->sh_addr); /* relocate the PLT */ if (file_type == TCC_OUTPUT_EXE) { uint8_t *p, *p_end; p = s1->plt->data; p_end = p + s1->plt->data_offset; if (p < p_end) { put32(p + 2, get32(p + 2) + s1->got->sh_addr); put32(p + 8, get32(p + 8) + s1->got->sh_addr); p += 16; while (p < p_end) { put32(p + 2, get32(p + 2) + s1->got->sh_addr); p += 16; } } } /* relocate symbols in .dynsym */ sym_end = (Elf32_Sym *)(s1->dynsym->data + s1->dynsym->data_offset); for(sym = (Elf32_Sym *)s1->dynsym->data + 1; sym < sym_end; sym++) { if (sym->st_shndx == SHN_UNDEF) { /* relocate to the PLT if the symbol corresponds to a PLT entry */ if (sym->st_value) sym->st_value += s1->plt->sh_addr; } else if (sym->st_shndx < SHN_LORESERVE) { /* do symbol relocation */ sym->st_value += s1->sections[sym->st_shndx]->sh_addr; } } /* put dynamic section entries */ dynamic->data_offset = saved_dynamic_data_offset; put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); put_dt(dynamic, DT_STRTAB, dynstr->sh_addr); put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); 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 ? */ } 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 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_386; 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; /* write elf file */ if (file_type == TCC_OUTPUT_OBJ) mode = 0666; else mode = 0777; fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, mode); if (fd < 0) { error_noabort("could not write '%s'", filename); goto fail; } f = fdopen(fd, "w"); 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; } } while (offset < ehdr.e_shoff) { fputc(0, f); offset++; } /* output section headers */ 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); } 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_386) { 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -