📄 tccelf.c
字号:
build_got(s1); /* scan for undefined symbols and see if they are in the dynamic symbols. If a symbol STT_FUNC is found, then we add it in the PLT. If a symbol STT_OBJECT is found, we add it in the .bss section with a suitable relocation */ sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); if (file_type == TCC_OUTPUT_EXE) { for(sym = (Elf32_Sym *)symtab_section->data + 1; sym < sym_end; sym++) { if (sym->st_shndx == SHN_UNDEF) { name = symtab_section->link->data + sym->st_name; sym_index = find_elf_sym(s1->dynsymtab_section, name); if (sym_index) { esym = &((Elf32_Sym *)s1->dynsymtab_section->data)[sym_index]; type = ELF32_ST_TYPE(esym->st_info); if (type == STT_FUNC) { put_got_entry(s1, R_JMP_SLOT, esym->st_size, esym->st_info, sym - (Elf32_Sym *)symtab_section->data); } else if (type == STT_OBJECT) { unsigned long offset; offset = bss_section->data_offset; /* XXX: which alignment ? */ offset = (offset + 16 - 1) & -16; index = put_elf_sym(s1->dynsym, offset, esym->st_size, esym->st_info, 0, bss_section->sh_num, name); put_elf_reloc(s1->dynsym, bss_section, offset, R_COPY, index); offset += esym->st_size; bss_section->data_offset = offset; } } else { /* STB_WEAK undefined symbols are accepted */ /* XXX: _fp_hw seems to be part of the ABI, so we ignore it */ if (ELF32_ST_BIND(sym->st_info) == STB_WEAK || !strcmp(name, "_fp_hw")) { } else { error_noabort("undefined symbol '%s'", name); } } } else if (s1->rdynamic && ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { /* if -rdynamic option, then export all non local symbols */ name = symtab_section->link->data + sym->st_name; put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info, 0, sym->st_shndx, name); } } if (s1->nb_errors) goto fail; /* now look at unresolved dynamic symbols and export corresponding symbol */ sym_end = (Elf32_Sym *)(s1->dynsymtab_section->data + s1->dynsymtab_section->data_offset); for(esym = (Elf32_Sym *)s1->dynsymtab_section->data + 1; esym < sym_end; esym++) { if (esym->st_shndx == SHN_UNDEF) { name = s1->dynsymtab_section->link->data + esym->st_name; sym_index = find_elf_sym(symtab_section, name); if (sym_index) { /* XXX: avoid adding a symbol if already present because of -rdynamic ? */ sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info, 0, sym->st_shndx, name); } else { if (ELF32_ST_BIND(esym->st_info) == STB_WEAK) { /* weak symbols can stay undefined */ } else { warning("undefined dynamic symbol '%s'", name); } } } } } else { int nb_syms; /* shared library case : we simply export all the global symbols */ nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym); s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); for(sym = (Elf32_Sym *)symtab_section->data + 1; sym < sym_end; sym++) { if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { name = symtab_section->link->data + sym->st_name; index = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info, 0, sym->st_shndx, name); s1->symtab_to_dynsym[sym - (Elf32_Sym *)symtab_section->data] = index; } } } build_got_entries(s1); /* add a list of needed dlls */ for(i = 0; i < s1->nb_loaded_dlls; i++) { DLLReference *dllref = s1->loaded_dlls[i]; if (dllref->level == 0) put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); } /* XXX: currently, since we do not handle PIC code, we must relocate the readonly segments */ if (file_type == TCC_OUTPUT_DLL) put_dt(dynamic, DT_TEXTREL, 0); /* add necessary space for other entries */ saved_dynamic_data_offset = dynamic->data_offset; dynamic->data_offset += 8 * 9; } else { /* still need to build got entries in case of static link */ build_got_entries(s1); } } memset(&ehdr, 0, sizeof(ehdr)); /* we add a section for symbols */ strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); put_elf_str(strsec, ""); /* compute number of sections */ shnum = s1->nb_sections; /* this array is used to reorder sections in the output file */ section_order = tcc_malloc(sizeof(int) * shnum); section_order[0] = 0; sh_order_index = 1; /* compute number of program headers */ switch(file_type) { default: case TCC_OUTPUT_OBJ: phnum = 0; break; case TCC_OUTPUT_EXE: if (!s1->static_link) phnum = 4; else phnum = 2; break; case TCC_OUTPUT_DLL: phnum = 3; break; } /* allocate strings for section names and decide if an unallocated section should be output */ /* NOTE: the strsec section comes last, so its size is also correct ! */ for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; s->sh_name = put_elf_str(strsec, s->name); /* when generating a DLL, we include relocations but we may patch them */ if (file_type == TCC_OUTPUT_DLL && s->sh_type == SHT_REL && !(s->sh_flags & SHF_ALLOC)) { prepare_dynamic_rel(s1, s); } else if (do_debug || file_type == TCC_OUTPUT_OBJ || (s->sh_flags & SHF_ALLOC) || i == (s1->nb_sections - 1)) { /* we output all sections if debug or object file */ s->sh_size = s->data_offset; } } /* allocate program segment headers */ phdr = tcc_mallocz(phnum * sizeof(Elf32_Phdr)); if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr); } else { file_offset = 0; } if (phnum > 0) { /* compute section to program header mapping */ if (s1->has_text_addr) { int a_offset, p_offset; addr = s1->text_addr; /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % ELF_PAGE_SIZE */ a_offset = addr & (ELF_PAGE_SIZE - 1); p_offset = file_offset & (ELF_PAGE_SIZE - 1); if (a_offset < p_offset) a_offset += ELF_PAGE_SIZE; file_offset += (a_offset - p_offset); } else { if (file_type == TCC_OUTPUT_DLL) addr = 0; else addr = ELF_START_ADDR; /* compute address after headers */ addr += (file_offset & (ELF_PAGE_SIZE - 1)); } /* dynamic relocation table information, for .dynamic section */ rel_size = 0; rel_addr = 0; /* 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 = addr; addr = (addr + s->sh_addralign - 1) & ~(s->sh_addralign - 1); file_offset += addr - tmp; s->sh_offset = file_offset; 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 (j == 0) { if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { /* 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; } else { addr = (addr + ELF_PAGE_SIZE - 1) & ~(ELF_PAGE_SIZE - 1); file_offset = (file_offset + ELF_PAGE_SIZE - 1) & ~(ELF_PAGE_SIZE - 1); } } } /* 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) {#if defined(TCC_TARGET_I386) 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; }#elif defined(TCC_TARGET_ARM) int x; x=s1->got->sh_addr - s1->plt->sh_addr - 12; p +=16; while (p < p_end) { put32(p + 12, x + get32(p + 12) + s1->plt->data - p); p += 16; }#elif defined(TCC_TARGET_C67) /* XXX: TODO */#else#error unsupported CPU#endif } } /* 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -