Remove ExtractCodeAndPrelink and switch Portable to MCLinker

Change-Id: Ia2459c7da6b79e0a1c0f1148c6e28ad9cbbe27a2
diff --git a/src/elf_file.cc b/src/elf_file.cc
index 8d6e630..6f9d53c 100644
--- a/src/elf_file.cc
+++ b/src/elf_file.cc
@@ -36,7 +36,9 @@
   dynsym_section_start_(NULL),
   strtab_section_start_(NULL),
   dynstr_section_start_(NULL),
-  hash_section_start_(NULL) {}
+  hash_section_start_(NULL),
+  symtab_symbol_table_(NULL),
+  dynsym_symbol_table_(NULL) {}
 
 ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only) {
   UniquePtr<ElfFile> elf_file(new ElfFile());
@@ -61,28 +63,34 @@
     prot = PROT_READ;
     flags = MAP_PRIVATE;
   }
-  if (file->GetLength() < sizeof(llvm::ELF::Elf32_Ehdr)) {
-    LOG(WARNING) << "File not large enough to contain ELF header: " << file->GetPath();
+  int64_t file_length = file_->GetLength();
+  if (file_length < 0) {
+    errno = -file_length;
+    PLOG(WARNING) << "Failed to get length of file: " << file_->GetPath() << " fd=" << file_->Fd();
+    return false;
+  }
+  if (file_length < sizeof(llvm::ELF::Elf32_Ehdr)) {
+    LOG(WARNING) << "File not large enough to contain ELF header: " << file_->GetPath();
     return false;
   }
 
   if (program_header_only) {
     // first just map ELF header to get program header size information
     size_t elf_header_size = sizeof(llvm::ELF::Elf32_Ehdr);
-    if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file->Fd(), 0))) {
-      LOG(WARNING) << "Failed to map ELF header: " << file->GetPath();
+    if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0))) {
+      LOG(WARNING) << "Failed to map ELF header: " << file_->GetPath();
       return false;
     }
     // then remap to cover program header
     size_t program_header_size = header_->e_phoff + (header_->e_phentsize * header_->e_phnum);
-    if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file->Fd(), 0))) {
-      LOG(WARNING) << "Failed to map ELF program headers: " << file->GetPath();
+    if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0))) {
+      LOG(WARNING) << "Failed to map ELF program headers: " << file_->GetPath();
       return false;
     }
   } else {
     // otherwise map entire file
-    if (!SetMap(MemMap::MapFile(file->GetLength(), prot, flags, file->Fd(), 0))) {
-      LOG(WARNING) << "Failed to map ELF file: " << file->GetPath();
+    if (!SetMap(MemMap::MapFile(file_->GetLength(), prot, flags, file_->Fd(), 0))) {
+      LOG(WARNING) << "Failed to map ELF file: " << file_->GetPath();
       return false;
     }
   }
@@ -97,7 +105,7 @@
     // Find .dynamic section info from program header
     dynamic_program_header_ = FindProgamHeaderByType(llvm::ELF::PT_DYNAMIC);
     if (dynamic_program_header_ == NULL) {
-      LOG(WARNING) << "Failed to find PT_DYNAMIC program header in ELF file: " << file->GetPath();
+      LOG(WARNING) << "Failed to find PT_DYNAMIC program header in ELF file: " << file_->GetPath();
       return false;
     }
 
@@ -129,7 +137,7 @@
         case llvm::ELF::SHT_DYNAMIC: {
           if (reinterpret_cast<byte*>(dynamic_section_start_) != section_addr) {
             LOG(WARNING) << "Failed to find matching SHT_DYNAMIC for PT_DYNAMIC in "
-                         << file->GetPath() << ": " << std::hex
+                         << file_->GetPath() << ": " << std::hex
                          << reinterpret_cast<void*>(dynamic_section_start_)
                          << " != " << reinterpret_cast<void*>(section_addr);
             return false;
@@ -148,6 +156,8 @@
 
 ElfFile::~ElfFile() {
   STLDeleteElements(&segments_);
+  delete symtab_symbol_table_;
+  delete dynsym_symbol_table_;
 }
 
 bool ElfFile::SetMap(MemMap* map) {
@@ -247,9 +257,9 @@
   return symbol_section_start;
 }
 
-char* ElfFile::GetSymbolStringSectionStart(llvm::ELF::Elf32_Word section_type) {
+const char* ElfFile::GetStringSectionStart(llvm::ELF::Elf32_Word section_type) {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
-  char* string_section_start;
+  const char* string_section_start;
   switch (section_type) {
     case llvm::ELF::SHT_SYMTAB: {
       string_section_start = strtab_section_start_;
@@ -268,6 +278,16 @@
   return string_section_start;
 }
 
+const char* ElfFile::GetString(llvm::ELF::Elf32_Word section_type, llvm::ELF::Elf32_Word i) {
+  CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
+  if (i == 0) {
+    return NULL;
+  }
+  const char* string_section_start = GetStringSectionStart(section_type);
+  const char* string = string_section_start + i;
+  return string;
+}
+
 llvm::ELF::Elf32_Word* ElfFile::GetHashSectionStart() {
   CHECK(hash_section_start_ != NULL);
   return hash_section_start_;
@@ -342,28 +362,30 @@
 }
 
 // from bionic
-static unsigned elfhash(const char *_name)
-{
-    const unsigned char *name = (const unsigned char *) _name;
-    unsigned h = 0, g;
+static unsigned elfhash(const char *_name) {
+  const unsigned char *name = (const unsigned char *) _name;
+  unsigned h = 0, g;
 
-    while(*name) {
-        h = (h << 4) + *name++;
-        g = h & 0xf0000000;
-        h ^= g;
-        h ^= g >> 24;
-    }
-    return h;
+  while(*name) {
+    h = (h << 4) + *name++;
+    g = h & 0xf0000000;
+    h ^= g;
+    h ^= g >> 24;
+  }
+  return h;
+}
+
+llvm::ELF::Elf32_Shdr& ElfFile::GetSectionNameStringSection() {
+  return GetSectionHeader(GetHeader().e_shstrndx);
 }
 
 byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) {
   llvm::ELF::Elf32_Word hash = elfhash(symbol_name.c_str());
   llvm::ELF::Elf32_Word bucket_index = hash % GetHashBucketNum();
   llvm::ELF::Elf32_Word symbol_and_chain_index = GetHashBucket(bucket_index);
-  char* symbol_string_section_start = GetSymbolStringSectionStart(llvm::ELF::SHT_DYNSYM);
   while (symbol_and_chain_index != 0 /* STN_UNDEF */) {
     llvm::ELF::Elf32_Sym& symbol = GetSymbol(llvm::ELF::SHT_DYNSYM, symbol_and_chain_index);
-    char* name = symbol_string_section_start + symbol.st_name;
+    const char* name = GetString(llvm::ELF::SHT_DYNSYM, symbol.st_name);
     if (symbol_name == name) {
       return base_address_ + symbol.st_value;
     }
@@ -387,10 +409,66 @@
   return *(GetSymbolSectionStart(section_type) + i);
 }
 
+ElfFile::SymbolTable** ElfFile::GetSymbolTable(llvm::ELF::Elf32_Word section_type) {
+  CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
+  switch (section_type) {
+    case llvm::ELF::SHT_SYMTAB: {
+      return &symtab_symbol_table_;
+    }
+    case llvm::ELF::SHT_DYNSYM: {
+      return &dynsym_symbol_table_;
+    }
+    default: {
+      LOG(FATAL) << section_type;
+      return NULL;
+    }
+  }
+}
+
 llvm::ELF::Elf32_Sym* ElfFile::FindSymbolByName(llvm::ELF::Elf32_Word section_type,
-                                                const std::string& symbol_name) {
+                                                const std::string& symbol_name,
+                                                bool build_map) {
   CHECK(!program_header_only_) << file_->GetPath();
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
+
+  SymbolTable** symbol_table = GetSymbolTable(section_type);
+  if (*symbol_table != NULL || build_map) {
+    if (*symbol_table == NULL) {
+      DCHECK(build_map);
+      *symbol_table = new SymbolTable;
+      llvm::ELF::Elf32_Shdr* symbol_section = FindSectionByType(section_type);
+      CHECK(symbol_section != NULL) << file_->GetPath();
+      llvm::ELF::Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
+      for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
+        llvm::ELF::Elf32_Sym& symbol = GetSymbol(section_type, i);
+        unsigned char type = symbol.getType();
+        if (type == llvm::ELF::STT_NOTYPE) {
+          continue;
+        }
+        const char* name = GetString(string_section, symbol.st_name);
+        if (name == NULL) {
+          continue;
+        }
+        std::pair<SymbolTable::iterator, bool> result = (*symbol_table)->insert(std::make_pair(name, &symbol));
+        if (!result.second) {
+          // If a duplicate, make sure it has the same logical value. Seen on x86.
+          CHECK_EQ(symbol.st_value, result.first->second->st_value);
+          CHECK_EQ(symbol.st_size, result.first->second->st_size);
+          CHECK_EQ(symbol.st_info, result.first->second->st_info);
+          CHECK_EQ(symbol.st_other, result.first->second->st_other);
+          CHECK_EQ(symbol.st_shndx, result.first->second->st_shndx);
+        }
+      }
+    }
+    CHECK(*symbol_table != NULL);
+    SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name);
+    if (it == (*symbol_table)->end()) {
+      return NULL;
+    }
+    return it->second;
+  }
+
+  // Fall back to linear search
   llvm::ELF::Elf32_Shdr* symbol_section = FindSectionByType(section_type);
   CHECK(symbol_section != NULL) << file_->GetPath();
   llvm::ELF::Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
@@ -408,15 +486,16 @@
 }
 
 llvm::ELF::Elf32_Addr ElfFile::FindSymbolAddress(llvm::ELF::Elf32_Word section_type,
-                                                 const std::string& symbol_name) {
-  llvm::ELF::Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name);
+                                                 const std::string& symbol_name,
+                                                 bool build_map) {
+  llvm::ELF::Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map);
   if (symbol == NULL) {
     return 0;
   }
   return symbol->st_value;
 }
 
-char* ElfFile::GetString(llvm::ELF::Elf32_Shdr& string_section, llvm::ELF::Elf32_Word i) {
+const char* ElfFile::GetString(llvm::ELF::Elf32_Shdr& string_section, llvm::ELF::Elf32_Word i) {
   CHECK(!program_header_only_) << file_->GetPath();
   // TODO: remove this static_cast from enum when using -std=gnu++0x
   CHECK_EQ(static_cast<llvm::ELF::Elf32_Word>(llvm::ELF::SHT_STRTAB), string_section.sh_type) << file_->GetPath();
@@ -427,7 +506,7 @@
   byte* strings = Begin() + string_section.sh_offset;
   byte* string = strings + i;
   CHECK_LT(string, End()) << file_->GetPath();
-  return reinterpret_cast<char*>(string);
+  return reinterpret_cast<const char*>(string);
 }
 
 llvm::ELF::Elf32_Word ElfFile::GetDynamicNum() {
@@ -439,6 +518,50 @@
   return *(GetDynamicSectionStart() + i);
 }
 
+llvm::ELF::Elf32_Word ElfFile::FindDynamicValueByType(llvm::ELF::Elf32_Sword type) {
+  for (llvm::ELF::Elf32_Word i = 0; i < GetDynamicNum(); i++) {
+    llvm::ELF::Elf32_Dyn& elf_dyn = GetDynamic(i);
+    if (elf_dyn.d_tag == type) {
+      return elf_dyn.d_un.d_val;
+    }
+  }
+  return 0;
+}
+
+llvm::ELF::Elf32_Rel* ElfFile::GetRelSectionStart(llvm::ELF::Elf32_Shdr& section_header) {
+  CHECK(llvm::ELF::SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  return reinterpret_cast<llvm::ELF::Elf32_Rel*>(Begin() + section_header.sh_offset);
+}
+
+llvm::ELF::Elf32_Word ElfFile::GetRelNum(llvm::ELF::Elf32_Shdr& section_header) {
+  CHECK(llvm::ELF::SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  CHECK_NE(0U, section_header.sh_entsize) << file_->GetPath();
+  return section_header.sh_size / section_header.sh_entsize;
+}
+
+llvm::ELF::Elf32_Rel& ElfFile::GetRel(llvm::ELF::Elf32_Shdr& section_header, llvm::ELF::Elf32_Word i) {
+  CHECK(llvm::ELF::SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  CHECK_LT(i, GetRelNum(section_header)) << file_->GetPath();
+  return *(GetRelSectionStart(section_header) + i);
+}
+
+llvm::ELF::Elf32_Rela* ElfFile::GetRelaSectionStart(llvm::ELF::Elf32_Shdr& section_header) {
+  CHECK(llvm::ELF::SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  return reinterpret_cast<llvm::ELF::Elf32_Rela*>(Begin() + section_header.sh_offset);
+}
+
+llvm::ELF::Elf32_Word ElfFile::GetRelaNum(llvm::ELF::Elf32_Shdr& section_header) {
+  CHECK(llvm::ELF::SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  return section_header.sh_size / section_header.sh_entsize;
+}
+
+llvm::ELF::Elf32_Rela& ElfFile::GetRela(llvm::ELF::Elf32_Shdr& section_header,
+                                        llvm::ELF::Elf32_Word i) {
+  CHECK(llvm::ELF::SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  CHECK_LT(i, GetRelaNum(section_header)) << file_->GetPath();
+  return *(GetRelaSectionStart(section_header) + i);
+}
+
 // Base on bionic phdr_table_get_load_size
 size_t ElfFile::GetLoadedSize() {
   llvm::ELF::Elf32_Addr min_vaddr = 0xFFFFFFFFu;
@@ -528,6 +651,7 @@
     CHECK_EQ(segment->Begin(), p_vaddr) << file_->GetPath();
     segments_.push_back(segment.release());
   }
+
   // Now that we are done loading, .dynamic should be in memory to find .dynstr, .dynsym, .hash
   dynamic_section_start_
       = reinterpret_cast<llvm::ELF::Elf32_Dyn*>(base_address_ + GetDynamicProgramHeader().p_vaddr);
@@ -549,6 +673,7 @@
       }
       case llvm::ELF::DT_NULL: {
         CHECK_EQ(GetDynamicNum(), i+1);
+        break;
       }
     }
   }