1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file. 4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_elf_symbols.h" 6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_debug.h" 8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_elf_view.h" 9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace crazy { 11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace { 13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Compute the ELF hash of a given symbol. 15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)unsigned ElfHash(const char* name) { 16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name); 17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) unsigned h = 0; 18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while (*ptr) { 19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) h = (h << 4) + *ptr++; 20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) unsigned g = h & 0xf0000000; 21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) h ^= g; 22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) h ^= g >> 24; 23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return h; 25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace 28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfSymbols::Init(const ElfView* view) { 30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) LOG("%s: Parsing dynamic table\n", __FUNCTION__); 31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ElfView::DynamicIterator dyn(view); 32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (; dyn.HasNext(); dyn.GetNext()) { 33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uintptr_t dyn_addr = dyn.GetAddress(view->load_bias()); 34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) switch (dyn.GetTag()) { 35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case DT_HASH: 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) LOG(" DT_HASH addr=%p\n", dyn_addr); 37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) { 38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Word* data = reinterpret_cast<ELF::Word*>(dyn_addr); 39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hash_bucket_size_ = data[0]; 40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hash_chain_size_ = data[1]; 41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hash_bucket_ = data + 2; 42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hash_chain_ = data + 2 + hash_bucket_size_; 43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) break; 45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case DT_STRTAB: 46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) LOG(" DT_STRTAB addr=%p\n", dyn_addr); 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) string_table_ = reinterpret_cast<const char*>(dyn_addr); 48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) break; 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case DT_SYMTAB: 50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) LOG(" DT_SYMTAB addr=%p\n", dyn_addr); 51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) symbol_table_ = reinterpret_cast<const ELF::Sym*>(dyn_addr); 52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) break; 53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) default: 54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ; 55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (symbol_table_ == NULL || string_table_ == NULL || hash_bucket_ == NULL) 58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const ELF::Sym* ElfSymbols::LookupByAddress(void* address, 64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t load_bias) const { 65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr elf_addr = 66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) reinterpret_cast<ELF::Addr>(address) - static_cast<ELF::Addr>(load_bias); 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (size_t n = 0; n < hash_chain_size_; ++n) { 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Sym* sym = &symbol_table_[n]; 70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (sym->st_shndx != SHN_UNDEF && elf_addr >= sym->st_value && 71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elf_addr < sym->st_value + sym->st_size) { 72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return sym; 73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return NULL; 76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfSymbols::LookupNearestByAddress(void* address, 79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t load_bias, 80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const char** sym_name, 81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) void** sym_addr, 82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t* sym_size) const { 83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr elf_addr = 84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) reinterpret_cast<ELF::Addr>(address) - static_cast<ELF::Addr>(load_bias); 85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Sym* nearest_sym = NULL; 87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t nearest_diff = ~size_t(0); 88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (size_t n = 0; n < hash_chain_size_; ++n) { 90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Sym* sym = &symbol_table_[n]; 91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (sym->st_shndx == SHN_UNDEF) 92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (elf_addr >= sym->st_value && elf_addr < sym->st_value + sym->st_size) { 95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // This is a perfect match. 96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) nearest_sym = sym; 97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) break; 98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Otherwise, compute distance. 101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t diff; 102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (elf_addr < sym->st_value) 103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) diff = sym->st_value - elf_addr; 104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) else 105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) diff = elf_addr - sym->st_value - sym->st_size; 106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (diff < nearest_diff) { 108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) nearest_sym = sym; 109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) nearest_diff = diff; 110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!nearest_sym) 114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *sym_name = string_table_ + nearest_sym->st_name; 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *sym_addr = reinterpret_cast<void*>(nearest_sym->st_value + load_bias); 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *sym_size = nearest_sym->st_size; 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const ELF::Sym* ElfSymbols::LookupByName(const char* symbol_name) const { 123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) unsigned hash = ElfHash(symbol_name); 124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (unsigned n = hash_bucket_[hash % hash_bucket_size_]; n != 0; 126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) n = hash_chain_[n]) { 127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Sym* symbol = &symbol_table_[n]; 128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Check that the symbol has the appropriate name. 129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (strcmp(string_table_ + symbol->st_name, symbol_name)) 130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Ignore undefined symbols. 132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (symbol->st_shndx == SHN_UNDEF) 133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Ignore anything that isn't a global or weak definition. 135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) switch (ELF_ST_BIND(symbol->st_info)) { 136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case STB_GLOBAL: 137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case STB_WEAK: 138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return symbol; 139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) default: 140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ; 141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return NULL; 144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace crazy 147