同步操作将从 Gitee 极速下载/Halide 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
#include "Elf.h"#include "Debug.h"#include "Error.h"#include "Util.h"#include <algorithm>#include <array>#include <iomanip>#include <map>#include <memory>namespace Halide {namespace Internal {namespace Elf {namespace {// http://www.skyfree.org/linux/references/ELF_Format.pdfenum : uint32_t {PT_NULL = 0,PT_LOAD = 1,PT_DYNAMIC = 2,PT_INTERP = 3,PT_NOTE = 4,PT_SHLIB = 5,PT_PHDR = 6,PT_LOPROC = 0x70000000,PT_HIPROC = 0x7fffffff,};enum : uint32_t {PF_X = 1,PF_W = 2,PF_R = 4,PF_MASKOS = 0x0ff00000,PF_MASKPROC = 0xf0000000,};enum : uint32_t {DT_NULL = 0,DT_NEEDED = 1,DT_PLTRELSZ = 2,DT_PLTGOT = 3,DT_HASH = 4,DT_STRTAB = 5,DT_SYMTAB = 6,DT_RELA = 7,DT_RELASZ = 8,DT_RELAENT = 9,DT_STRSZ = 10,DT_SYMENT = 11,DT_INIT = 12,DT_FINI = 13,DT_SONAME = 14,DT_RPATH = 15,DT_SYMBOLIC = 16,DT_REL = 17,DT_RELSZ = 18,DT_RELENT = 19,DT_PLTREL = 20,DT_DEBUG = 21,DT_TEXTREL = 22,DT_JMPREL = 23,DT_LOPROC = 0x70000000,DT_HIPROC = 0x7fffffff,};enum : uint32_t {STN_UNDEF = 0};const char elf_magic[] = {0x7f, 'E', 'L', 'F'};template<int bits>struct Types;template<>struct Types<32> {typedef uint32_t addr_t;typedef int32_t addr_off_t;};template<typename T>struct Ehdr {typedef typename T::addr_t addr_t;typedef typename T::addr_off_t addr_off_t;uint8_t e_ident[16];uint16_t e_type;uint16_t e_machine;uint32_t e_version;addr_t e_entry;addr_t e_phoff;addr_t e_shoff;uint32_t e_flags;uint16_t e_ehsize;uint16_t e_phentsize;uint16_t e_phnum;uint16_t e_shentsize;uint16_t e_shnum;uint16_t e_shstrndx;};template<typename T>struct Phdr {typedef typename T::addr_t addr_t;typedef typename T::addr_off_t addr_off_t;uint32_t p_type;uint32_t p_offset;addr_t p_vaddr;addr_t p_paddr;uint32_t p_filesz;uint32_t p_memsz;uint32_t p_flags;uint32_t p_align;};template<typename T>struct Shdr {typedef typename T::addr_t addr_t;typedef typename T::addr_off_t addr_off_t;uint32_t sh_name;uint32_t sh_type;addr_t sh_flags;addr_t sh_addr;addr_t sh_offset;addr_t sh_size;uint32_t sh_link;uint32_t sh_info;addr_t sh_addralign;addr_t sh_entsize;};template<typename T>struct Rel {typedef typename T::addr_t addr_t;typedef typename T::addr_off_t addr_off_t;const addr_t r_offset;const addr_t r_info;uint32_t r_type() const {if (sizeof(addr_t) == 8) {return r_info & 0xffffffff;} else {return r_info & 0xff;}}uint32_t r_sym() const {if (sizeof(addr_t) == 8) {return (uint64_t)r_info >> 32;} else {return r_info >> 8;}}Rel(addr_t offset, addr_t info): r_offset(offset), r_info(info) {}Rel(addr_t offset, uint32_t type, uint32_t sym): r_offset(offset), r_info(make_info(type, sym)) {}private:static addr_t make_info(uint32_t type, uint32_t sym) {if (sizeof(addr_t) == 8) {return (uint64_t)type | ((uint64_t)sym << 32);} else {return (type & 0xff) | (sym << 8);}}};template<typename T>struct Rela : public Rel<T> {typedef typename T::addr_t addr_t;typedef typename T::addr_off_t addr_off_t;const addr_off_t r_addend;Rela(addr_t offset, addr_t info, addr_off_t addend): Rel<T>(offset, info), r_addend(addend) {}Rela(addr_t offset, uint32_t type, uint32_t sym, addr_off_t addend): Rel<T>(offset, type, sym), r_addend(addend) {}};template<typename T>struct Sym;template<>struct Sym<Types<32>> {uint32_t st_name;uint32_t st_value;uint32_t st_size;uint8_t st_info;uint8_t st_other;uint16_t st_shndx;uint8_t get_binding() const {return st_info >> 4;}uint8_t get_type() const {return st_info & 0xf;}void set_binding_and_type(uint8_t binding, uint8_t type) {st_info = make_info(binding, type);}private:static uint8_t make_info(uint8_t binding, uint8_t type) {return (binding << 4) | (type & 0xf);}};template<typename T>struct Dyn {typedef typename T::addr_t addr_t;typedef typename T::addr_off_t addr_off_t;uint32_t d_tag;union {uint32_t d_val;addr_t d_ptr;};};class StringTable {// TODO: We could be smarter and find substrings in the existing// table, not just whole strings. It would probably be fine to just// put every substring of each new string into the cache.std::map<std::string, uint32_t> cache;public:std::vector<char> table;StringTable() {// For our cache to work, we need something in the table to// start with so index 0 isn't valid (it will be the empty// string).table.push_back(0);}uint32_t get(const std::string &str) {uint32_t &index = cache[str];if (index == 0) {index = table.size();table.insert(table.end(), str.begin(), str.end());table.push_back(0);}return index;}};const char *assert_string_valid(const char *name, const char *data, size_t size) {internal_assert(data <= name && name + strlen(name) + 1 <= data + size);return name;}template<typename T>void append_object(std::vector<char> &buf, const T &data) {buf.insert(buf.end(), (const char *)&data, (const char *)(&data + 1));}template<typename It>void append(std::vector<char> &buf, It begin, It end) {buf.reserve(buf.size() + std::distance(begin, end) * sizeof(*begin));for (It i = begin; i != end; i++) {append_object(buf, *i);}}void append_zeros(std::vector<char> &buf, size_t count) {buf.insert(buf.end(), count, (char)0);}void append_padding(std::vector<char> &buf, size_t alignment) {buf.resize((buf.size() + alignment - 1) & ~(alignment - 1));}// Cast one type to another, asserting that the type is in the range// of the target type.template<typename T, typename U>T safe_cast(U x) {internal_assert(std::numeric_limits<T>::min() <= x && x <= std::numeric_limits<T>::max());return static_cast<T>(x);}// Assign a type from a potentially different type, using safe_cast// above to validate the assignment.template<typename T, typename U>void safe_assign(T &dest, U src) {dest = safe_cast<T>(src);}unsigned long elf_hash(const char *name) {unsigned long h = 0;unsigned long g;for (char c = *name; c; c = *name++) {h = (h << 4) + c;g = h & 0xf0000000;if (g != 0) {h ^= g >> 24;}h &= ~g;}return h;}template<typename T>std::unique_ptr<Object> parse_object_internal(const char *data, size_t size) {Ehdr<T> header = *(const Ehdr<T> *)data;internal_assert(memcmp(header.e_ident, elf_magic, sizeof(elf_magic)) == 0);internal_assert(header.e_type == Object::ET_REL || header.e_type == Object::ET_DYN);std::unique_ptr<Object> obj(new Object());obj->set_type((Object::Type)header.e_type).set_machine(header.e_machine).set_version(header.e_version).set_entry(header.e_entry).set_flags(header.e_flags);auto get_section_header = [&](int idx) -> const Shdr<T> * {const char *at = data + header.e_shoff + idx * header.e_shentsize;internal_assert(data <= at && at + sizeof(Shdr<T>) <= data + size)<< "Section header out of bounds.\n";return (const Shdr<T> *)at;};// Find the string table.const char *strings = nullptr;for (int i = 0; i < header.e_shnum; i++) {const Shdr<T> *sh = get_section_header(i);if (sh->sh_type == Section::SHT_STRTAB) {internal_assert(!strings) << "Found more than one string table.\n";strings = data + sh->sh_offset;internal_assert(data <= strings && strings + sh->sh_size <= data + size);}}internal_assert(strings)<< "String table not found.\n";// Load the rest of the sections.std::map<int, Section *> section_map;for (uint16_t i = 0; i < header.e_shnum; i++) {const Shdr<T> *sh = get_section_header(i);if (sh->sh_type != Section::SHT_SYMTAB && sh->sh_type != Section::SHT_STRTAB &&sh->sh_type != Section::SHT_REL && sh->sh_type != Section::SHT_RELA) {const char *name = assert_string_valid(&strings[sh->sh_name], data, size);auto section = obj->add_section(name, (Section::Type)sh->sh_type);section->set_flags(sh->sh_flags).set_size(sh->sh_size).set_alignment(sh->sh_addralign);if (sh->sh_type == Section::SHT_NOBITS) {// This section doesn't have any data to load.} else if (sh->sh_type == Section::SHT_NULL) {} else {const char *sh_data = data + sh->sh_offset;internal_assert(data <= sh_data && sh_data + sh->sh_size <= data + size);section->set_contents(sh_data, sh_data + sh->sh_size);}section_map[i] = &*section;}}// Find and load the symbols.std::map<int, Symbol *> symbol_map;for (uint16_t i = 0; i < header.e_shnum; i++) {const Shdr<T> *sh = get_section_header(i);if (sh->sh_type == Section::SHT_SYMTAB) {internal_assert(sh->sh_entsize == sizeof(Sym<T>));// Skip symbol 0, which is a null symbol.for (uint64_t j = 1; j < sh->sh_size / sizeof(Sym<T>); ++j) {const char *sym_ptr = data + sh->sh_offset + j * sizeof(Sym<T>);internal_assert(data <= sym_ptr && sym_ptr + sizeof(Sym<T>) <= data + size);const Sym<T> &sym = *(const Sym<T> *)sym_ptr;const char *name = assert_string_valid(&strings[sym.st_name], data, size);auto symbol = obj->add_symbol(name);symbol->set_type((Symbol::Type)sym.get_type()).set_binding((Symbol::Binding)sym.get_binding()).set_visibility((Symbol::Visibility)sym.st_other);if (sym.st_shndx != 0) {symbol->define(section_map[sym.st_shndx], sym.st_value, sym.st_size);}symbol_map[j] = &*symbol;}}}// Load relocations.for (uint16_t i = 0; i < header.e_shnum; i++) {const Shdr<T> *sh = get_section_header(i);internal_assert(sh->sh_type != Section::SHT_REL) << "Section::SHT_REL not supported\n";if (sh->sh_type == Section::SHT_RELA) {const char *name = assert_string_valid(&strings[sh->sh_name], data, size);internal_assert(strncmp(name, ".rela.", 6) == 0);internal_assert(sh->sh_entsize == sizeof(Rela<T>));auto to_relocate = obj->find_section(name + 5);internal_assert(to_relocate != obj->sections_end());// TODO: This assert should work, but it seems like this// isn't a reliable test. We rely on the names intead.// internal_assert(&*to_relocate == section_map[sh->sh_link]);for (uint64_t i = 0; i < sh->sh_size / sh->sh_entsize; i++) {const char *rela_ptr = data + sh->sh_offset + i * sh->sh_entsize;internal_assert(data <= rela_ptr && rela_ptr + sizeof(Rela<T>) <= data + size);const Rela<T> &rela = *(const Rela<T> *)rela_ptr;Relocation reloc(rela.r_type(), rela.r_offset, rela.r_addend, symbol_map[rela.r_sym()]);to_relocate->add_relocation(reloc);}}}return obj;}} // namespacestd::unique_ptr<Object> Object::parse_object(const char *data, size_t size) {return parse_object_internal<Types<32>>(data, size);}Object::symbol_iterator Object::add_symbol(const std::string &name) {syms.emplace_back(name);return std::prev(syms.end());}Object::section_iterator Object::add_section(const std::string &name, Section::Type type) {secs.emplace_back(name, type);return std::prev(secs.end());}Object::section_iterator Object::find_section(const std::string &name) {for (section_iterator i = sections_begin(); i != sections_end(); ++i) {if (i->get_name() == name) {return i;}}return sections_end();}Object::symbol_iterator Object::find_symbol(const std::string &name) {for (symbol_iterator i = symbols_begin(); i != symbols_end(); ++i) {if (i->get_name() == name) {return i;}}return symbols_end();}Object::const_symbol_iterator Object::find_symbol(const std::string &name) const {for (const_symbol_iterator i = symbols_begin(); i != symbols_end(); ++i) {if (i->get_name() == name) {return i;}}return symbols_end();}Object::section_iterator Object::merge_sections(const std::vector<section_iterator> &to_merge) {internal_assert(!to_merge.empty());section_iterator merged = *to_merge.begin();std::vector<char> contents = merged->get_contents();for (auto i = to_merge.begin() + 1; i != to_merge.end(); ++i) {section_iterator s = *i;internal_assert(s->get_type() == merged->get_type());// Make the new text section have an alignment that// satisfies all sections. This should be gcd, not max,// but we assume that all of the alignments are powers of// 2.uint64_t alignment = std::max(merged->get_alignment(), s->get_alignment());merged->set_alignment(alignment);append_padding(contents, alignment);// The offset of the section in the new merged section.uint64_t offset = contents.size();append(contents, s->contents_begin(), s->contents_end());for (auto j = s->relocations_begin(); j != s->relocations_end(); j++) {Elf::Relocation reloc = *j;reloc.set_offset(reloc.get_offset() + offset);merged->add_relocation(reloc);}// Find all of the symbols that were defined in this section, and update them.for (auto j = symbols_begin(); j != symbols_end(); j++) {if (j->get_section() == &*s) {j->define(&*merged, j->get_offset() + offset, j->get_size());}}}merged->set_contents(contents.begin(), contents.end());// Remove all of the sections we merged.for (auto i = to_merge.begin() + 1; i != to_merge.end(); ++i) {erase_section(*i);}return merged;}Object::section_iterator Object::merge_text_sections() {std::vector<section_iterator> text_sections;for (auto i = sections_begin(); i != sections_end(); i++) {if (i->get_type() == Section::SHT_PROGBITS && starts_with(i->get_name(), ".text")) {text_sections.push_back(i);}}section_iterator text = merge_sections(text_sections);text->set_name(".text");return text;}template<typename T>std::vector<char> write_shared_object_internal(Object &obj, Linker *linker, const std::vector<std::string> &dependencies,const std::string &soname) {typedef typename T::addr_t addr_t;// The buffer we will be writing to.std::vector<char> output;// Declare the things we need to put in the shared object.Ehdr<T> ehdr;std::array<Phdr<T>, 3> phdrs;memset(&ehdr, 0, sizeof(ehdr));memset(&phdrs[0], 0, sizeof(phdrs));auto &text_phdr = phdrs[0];auto &data_phdr = phdrs[1];auto &dyn_phdr = phdrs[2];// The text program header starts at the beginning of the object.text_phdr.p_type = PT_LOAD;text_phdr.p_flags = PF_X | PF_R;text_phdr.p_offset = 0;text_phdr.p_align = 4096;// We need to build a string table as we go.StringTable strings;// And build a list of section headers.std::vector<Shdr<T>> shdrs;// Add the null section now.Shdr<T> sh_null;memset(&sh_null, 0, sizeof(sh_null));shdrs.push_back(sh_null);// We also need a mapping of section objects to section headers.std::map<const Section *, uint16_t> section_idxs;// Define a helper function to write a section to the shared// object, making a section header for it.auto write_section = [&](const Section &s, uint64_t entsize) {uint64_t alignment = s.get_alignment();append_padding(output, alignment);uint64_t offset = output.size();debug(2) << "Writing section " << s.get_name() << " at offset " << offset << "\n";const std::vector<char> &contents = s.get_contents();append(output, contents.begin(), contents.end());if (contents.size() < s.get_size()) {append_zeros(output, s.get_size() - contents.size());}append_padding(output, alignment);Shdr<T> shdr;shdr.sh_name = strings.get(s.get_name());safe_assign(shdr.sh_type, s.get_type());safe_assign(shdr.sh_flags, s.get_flags());safe_assign(shdr.sh_offset, offset);safe_assign(shdr.sh_addr, offset);safe_assign(shdr.sh_size, s.get_size());safe_assign(shdr.sh_addralign, alignment);shdr.sh_link = 0;shdr.sh_info = 0;safe_assign(shdr.sh_entsize, entsize);uint16_t shndx = safe_cast<uint16_t>(shdrs.size());section_idxs[&s] = shndx;shdrs.push_back(shdr);return shndx;};// And a helper to get the offset we've given a section.auto get_section_offset = [&](const Section &s) -> uint64_t {uint16_t idx = section_idxs[&s];return shdrs[idx].sh_offset;};// We need to define the GOT symbol.uint64_t max_got_size = obj.symbols_size() * 2 * sizeof(addr_t);Section got(".got", Section::SHT_PROGBITS);got.set_alignment(4);got.set_size(max_got_size);got.set_flags(Section::SHF_ALLOC);Symbol got_sym("_GLOBAL_OFFSET_TABLE_");got_sym.define(&got, 0, max_got_size);got_sym.set_type(Symbol::STT_OBJECT);got_sym.set_visibility(Symbol::STV_HIDDEN);Symbol dynamic_sym("_DYNAMIC");dynamic_sym.define(&got, 0, 4);dynamic_sym.set_type(Symbol::STT_OBJECT);got.append_contents((addr_t)0);// On some platforms, GOT slots 1 and 2 are also reserved.got.append_contents((addr_t)0);got.append_contents((addr_t)0);// Since we can't change the object, start a map of all of the// symbols that we can mutate. If a symbol from the object is a// key in this map, we use the mapped value instead.std::map<const Symbol *, const Symbol *> symbols;symbols[&dynamic_sym] = &dynamic_sym;Object::section_iterator iter_dtors = obj.find_section(".dtors");Symbol dtor_list_sym("__DTOR_LIST__");if (iter_dtors != obj.sections_end()) {Section *dtors = &(*iter_dtors);dtor_list_sym.define(dtors, 0, 0);dtor_list_sym.set_type(Symbol::STT_NOTYPE);dtor_list_sym.set_visibility(Symbol::STV_DEFAULT);dtor_list_sym.set_binding(Symbol::STB_GLOBAL);}Object::section_iterator iter_ctors = obj.find_section(".ctors");Symbol ctor_end_sym("__CTOR_END__");if (iter_ctors != obj.sections_end()) {Section *ctors = &(*iter_ctors);internal_assert(ctors->get_size() == ctors->contents_size())<< "There should no padding at the end of the .ctors section\n";ctor_end_sym.define(ctors, ctors->get_size(), 0);ctor_end_sym.set_type(Symbol::STT_NOTYPE);ctor_end_sym.set_visibility(Symbol::STV_DEFAULT);ctor_end_sym.set_binding(Symbol::STB_GLOBAL);}for (const Symbol &i : obj.symbols()) {if (i.get_name() == "_GLOBAL_OFFSET_TABLE_") {symbols[&i] = &got_sym;} else if (i.get_name() == "__DTOR_LIST__") {// It is our job to create this symbol. So, a defined __DTOR_LIST__// symbol shouldn't be present already.internal_assert(!i.is_defined()) << "__DTOR_LIST__ already defined\n";symbols[&i] = &dtor_list_sym;} else if (i.get_name() == "__CTOR_END__") {internal_assert(!i.is_defined()) << "__CTOR_END__ already defined\n";symbols[&i] = &ctor_end_sym;} else {symbols[&i] = &i;}}// Get a symbol from a relocation, accounting for the symbol map// above.auto get_symbol = [&](const Relocation &r) {const Symbol *sym = r.get_symbol();if (!sym) {return sym;}auto i = symbols.find(sym);if (i != symbols.end()) {return i->second;}return sym;};// Check if a relocation needs a PLT entry, which adds some// additional conditions on top of what the linker implementation// wants.auto needs_plt_entry = [&](const Relocation &r) {const Symbol *s = get_symbol(r);if (!s || s->is_defined()) {return false;}if (s->get_type() != Symbol::STT_NOTYPE) {return false;}return linker->needs_plt_entry(r);};// We need to build the PLT, so it can be positioned along with// the rest of the text sections.Section plt(".plt", Section::SHT_PROGBITS);plt.set_alignment(16);plt.set_flags(Section::SHF_ALLOC | Section::SHF_EXECINSTR);std::list<Symbol> plt_symbols;std::map<const Symbol *, const Symbol *> plt_defs;// Hack: We're defining the global offset table, so it shouldn't be treated as an external symbol.plt_defs[&got_sym] = &got_sym;for (const Section &s : obj.sections()) {for (const Relocation &r : s.relocations()) {if (!needs_plt_entry(r)) {continue;}const Symbol *sym = get_symbol(r);const Symbol *&plt_def = plt_defs[sym];if (plt_def) {// We already made a PLT entry for this symbol.continue;}debug(2) << "Defining PLT entry for " << sym->get_name() << "\n";plt_symbols.push_back(linker->add_plt_entry(*sym, plt, got, got_sym));plt_def = &plt_symbols.back();symbols[plt_def] = plt_def;}}// Start placing the sections into the shared object.// Leave room for the header, and program headers at the beginning of the file.append_zeros(output, sizeof(ehdr));append_zeros(output, sizeof(phdrs[0]) * 3);// We need to perform the relocations. To do that, we need to position the sections// where they will go in the final shared object.write_section(plt, 0);for (const Section &s : obj.sections()) {if (s.is_alloc() && !s.is_writable()) {write_section(s, 0);}}append_padding(output, 4096);text_phdr.p_filesz = output.size() - text_phdr.p_offset;data_phdr.p_type = PT_LOAD;data_phdr.p_flags = PF_W | PF_R;safe_assign(data_phdr.p_offset, output.size());data_phdr.p_align = 4096;for (const Section &s : obj.sections()) {if (s.is_alloc() && s.is_writable()) {write_section(s, 0);}}// The got will be written again later, after we add entries to it.write_section(got, 0);/// Now that we've written the sections that define symbols, we// can generate the symbol table.Section symtab(".symtab", Section::SHT_SYMTAB);symtab.set_alignment(4);symtab.set_flag(Section::SHF_ALLOC);std::vector<Sym<T>> syms;Sym<T> undef_sym;memset(&undef_sym, 0, sizeof(undef_sym));syms.push_back(undef_sym);// Ensure that we output the symbols deterministically, since a map of pointers// will vary in ordering from run to tun.std::vector<std::pair<const Symbol *, const Symbol *>> sorted_symbols;for (const auto &i : symbols) {sorted_symbols.emplace_back(i);}std::sort(sorted_symbols.begin(), sorted_symbols.end(),[&](const std::pair<const Symbol *, const Symbol *> &lhs, const std::pair<const Symbol *, const Symbol *> &rhs) {return lhs.first->get_name() < rhs.first->get_name();});std::map<const Symbol *, uint16_t> symbol_idxs;uint64_t local_count = 0;for (bool is_local : {true, false}) {for (const auto &i : sorted_symbols) {const Symbol *s = i.second;if ((s->get_binding() == Symbol::STB_LOCAL) != is_local) {continue;}uint64_t value = s->get_offset();// In shared objects, the symbol value is a virtual address,// not a section offset.if (s->is_defined()) {value += get_section_offset(*s->get_section());}Sym<T> sym;safe_assign(sym.st_name, strings.get(s->get_name()));safe_assign(sym.st_value, value);safe_assign(sym.st_size, s->get_size());sym.set_binding_and_type(s->get_binding(), s->get_type());safe_assign(sym.st_other, s->get_visibility());sym.st_shndx = section_idxs[s->get_section()];safe_assign(symbol_idxs[s], syms.size());syms.push_back(sym);}if (is_local) {local_count = syms.size();}}symtab.set_contents(syms);uint16_t symtab_idx = write_section(symtab, sizeof(syms[0]));safe_assign(shdrs[symtab_idx].sh_info, local_count);// Also write the symbol table as SHT_DYNSYM.Section dynsym = symtab;dynsym.set_name(".dynsym");dynsym.set_type(Section::SHT_DYNSYM);uint16_t dynsym_idx = write_section(dynsym, sizeof(syms[0]));shdrs[dynsym_idx].sh_info = local_count;// We really do need to make a hash table. Make a trivial one with one bucket.Section hash(".hash", Section::SHT_HASH);hash.set_alignment(4);hash.set_flag(Section::SHF_ALLOC);size_t sym_count = syms.size();// TODO: Fix non-trivial hash tables so they work with dlsym.size_t bucket_count = 1;std::vector<uint32_t> hash_table(bucket_count + sym_count + 2);safe_assign(hash_table[0], bucket_count);safe_assign(hash_table[1], sym_count);uint32_t *buckets = &hash_table[2];uint32_t *chains = buckets + bucket_count;for (size_t i = 0; i < sym_count; i++) {const char *name = &strings.table[syms[i].st_name];uint32_t hash = elf_hash(name) % bucket_count;chains[i] = buckets[hash];safe_assign(buckets[hash], i);}hash.set_contents(hash_table);uint16_t hash_idx = write_section(hash, sizeof(hash_table[0]));auto do_relocations = [&](const Section &s) {debug(2) << "Processing relocations for section " << s.get_name() << "\n";for (const Relocation &r : s.relocations()) {const Symbol *sym = get_symbol(r);if (needs_plt_entry(r)) {// This relocation is a function call, we need to use the PLT entry for this symbol.auto plt_def = plt_defs.find(sym);internal_assert(plt_def != plt_defs.end());debug(2) << "Using PLT entry " << plt_def->second->get_name() << " for symbol " << sym->get_name() << "\n";sym = plt_def->second;}uint64_t fixup_offset = get_section_offset(s) + r.get_offset();char *fixup_addr = output.data() + fixup_offset;uint64_t sym_offset = 0;if (sym && sym->is_defined()) {sym_offset = get_section_offset(*sym->get_section()) + sym->get_offset();debug(2) << "Symbol " << sym->get_name() << " is defined at " << sym_offset << "\n";}Relocation new_reloc = linker->relocate(fixup_offset, fixup_addr, r.get_type(), sym, sym_offset, r.get_addend(), got);if (new_reloc.get_type() != 0) {// The linker wants a dynamic relocation here. This// section must be writable at runtime.internal_assert(s.is_writable());debug(2) << "Linker returned new relocation type " << new_reloc.get_type() << "\n";new_reloc.set_offset(new_reloc.get_offset() - get_section_offset(got));got.add_relocation(new_reloc);}}};// Now that we've generated the symbol table, we can do relocations.do_relocations(plt);for (const Section &s : obj.sections()) {do_relocations(s);}// Now we can write the GOT.internal_assert(got.contents_size() <= max_got_size);memcpy(output.data() + get_section_offset(got), got.contents_data(), got.contents_size());auto write_relocation_section = [&](const Section &s) {uint64_t alignment = 8;append_padding(output, alignment);uint64_t offset = output.size();for (const Relocation &r : s.relocations()) {uint64_t i_offset = get_section_offset(s) + r.get_offset();Rela<T> rela(i_offset, r.get_type(), symbol_idxs[get_symbol(r)], r.get_addend());append_object(output, rela);}uint64_t size = output.size() - offset;append_padding(output, alignment);Shdr<T> shdr;safe_assign(shdr.sh_name, strings.get(".rela" + s.get_name()));shdr.sh_type = Section::SHT_RELA;shdr.sh_flags = Section::SHF_ALLOC;safe_assign(shdr.sh_offset, offset);safe_assign(shdr.sh_addr, offset);safe_assign(shdr.sh_size, size);safe_assign(shdr.sh_addralign, alignment);safe_assign(shdr.sh_link, symtab_idx);safe_assign(shdr.sh_info, section_idxs[&s]);shdr.sh_entsize = sizeof(Rela<T>);uint16_t shndx = safe_cast<uint16_t>(shdrs.size());shdrs.push_back(shdr);return shndx;};addr_t rela_got_idx = write_relocation_section(got);// Add some strings we know we'll need in the string table after we write it.strings.get(soname);for (const auto &i : dependencies) {strings.get(i);}Section dynamic(".dynamic", Section::SHT_DYNAMIC);strings.get(dynamic.get_name());dynamic.set_alignment(4);dynamic.set_flag(Section::SHF_ALLOC);Section strtab(".strtab", Section::SHT_STRTAB);strings.get(strtab.get_name());strtab.set_flag(Section::SHF_ALLOC);strtab.set_contents(strings.table);uint16_t strtab_idx = write_section(strtab, 0);std::vector<Dyn<T>> dyn;auto make_dyn = [](int32_t tag, addr_t val) {Dyn<T> d;d.d_tag = tag;d.d_val = val;return d;};for (const auto &i : dependencies) {dyn.push_back(make_dyn(DT_NEEDED, strings.get(i)));}if (!soname.empty()) {dyn.push_back(make_dyn(DT_SONAME, strings.get(soname)));}dyn.push_back(make_dyn(DT_SYMBOLIC, 0));// This is really required...dyn.push_back(make_dyn(DT_HASH, get_section_offset(hash)));// Address of the symbol table.dyn.push_back(make_dyn(DT_SYMTAB, shdrs[dynsym_idx].sh_offset));dyn.push_back(make_dyn(DT_SYMENT, shdrs[dynsym_idx].sh_entsize));// Address of the string table.dyn.push_back(make_dyn(DT_STRTAB, get_section_offset(strtab)));dyn.push_back(make_dyn(DT_STRSZ, strtab.get_size()));// Offset to the GOT.dyn.push_back(make_dyn(DT_PLTGOT, get_section_offset(got)));// Relocations associated with the PLT.addr_t pltrelsz = sizeof(Rela<T>) * plt_symbols.size();dyn.push_back(make_dyn(DT_JMPREL, shdrs[rela_got_idx].sh_offset));dyn.push_back(make_dyn(DT_PLTREL, DT_RELA));dyn.push_back(make_dyn(DT_PLTRELSZ, pltrelsz));// Other relocations.dyn.push_back(make_dyn(DT_RELA, shdrs[rela_got_idx].sh_offset + pltrelsz));dyn.push_back(make_dyn(DT_RELASZ, shdrs[rela_got_idx].sh_size - pltrelsz));dyn.push_back(make_dyn(DT_RELAENT, sizeof(Rela<T>)));// DT_FINIObject::section_iterator iter_fini = obj.find_section(".fini.halide");if (iter_fini != obj.sections_end()) {Section &fini = *iter_fini;dyn.push_back(make_dyn(DT_FINI, get_section_offset(fini)));}// DT_INITObject::section_iterator iter_init = obj.find_section(".init.halide");if (iter_init != obj.sections_end()) {Section &init = *iter_init;dyn.push_back(make_dyn(DT_INIT, get_section_offset(init)));}dynamic.set_contents(dyn);// Add any target specific stuff.linker->append_dynamic(dynamic);// Null terminator.dynamic.append_contents((uint32_t)DT_NULL);dynamic.append_contents((addr_t)0);uint16_t dyn_idx = write_section(dynamic, sizeof(dyn[0]));dyn_phdr.p_type = PT_DYNAMIC;dyn_phdr.p_offset = shdrs[dyn_idx].sh_offset;dyn_phdr.p_flags = PF_R;dyn_phdr.p_filesz = shdrs[dyn_idx].sh_size;dyn_phdr.p_memsz = dyn_phdr.p_filesz;dyn_phdr.p_align = 4;append_padding(output, 4096);safe_assign(data_phdr.p_filesz, output.size() - data_phdr.p_offset);// Setup the section headers.shdrs[symtab_idx].sh_link = strtab_idx;shdrs[dynsym_idx].sh_link = strtab_idx;shdrs[dyn_idx].sh_link = strtab_idx;shdrs[hash_idx].sh_link = dynsym_idx;// Write the section header table.ehdr.e_shoff = output.size();ehdr.e_shnum = shdrs.size();ehdr.e_shentsize = sizeof(shdrs[0]);for (auto &i : shdrs) {append_object(output, i);}// Now go back and write the headers.memcpy(ehdr.e_ident, elf_magic, 4);ehdr.e_ident[4] = 1;ehdr.e_ident[5] = 1;ehdr.e_ident[6] = 1;ehdr.e_type = Object::ET_DYN;ehdr.e_machine = linker->get_machine();ehdr.e_ehsize = sizeof(ehdr);ehdr.e_version = linker->get_version();ehdr.e_entry = obj.get_entry();ehdr.e_flags = linker->get_flags();ehdr.e_phoff = sizeof(ehdr);ehdr.e_phentsize = sizeof(phdrs[0]);ehdr.e_phnum = phdrs.size();ehdr.e_shstrndx = strtab_idx;memcpy(output.data(), &ehdr, sizeof(ehdr));for (auto &i : phdrs) {i.p_vaddr = i.p_offset;i.p_paddr = i.p_offset;i.p_memsz = i.p_filesz;}memcpy(output.data() + ehdr.e_phoff, phdrs.data(), sizeof(phdrs));return output;}std::vector<char> Object::write_shared_object(Linker *linker, const std::vector<std::string> &dependencies,const std::string &soname) {return write_shared_object_internal<Types<32>>(*this, linker, dependencies, soname);}} // namespace Elf} // namespace Internal} // namespace Halide
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。