// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CRAZY_LINKER_SHARED_LIBRARY_H #define CRAZY_LINKER_SHARED_LIBRARY_H #include #include "crazy_linker_elf_relro.h" #include "crazy_linker_elf_symbols.h" #include "crazy_linker_elf_view.h" #include "crazy_linker_error.h" #include "crazy_linker_rdebug.h" #include "crazy_linker_util.h" #include "elf_traits.h" namespace crazy { class LibraryList; class LibraryView; // A class that models a shared library loaded by the crazy linker. // Libraries have dependencies (which are listed in their dynamic section // as DT_NEEDED entries). Circular dependencies are forbidden, so they // form an ADG, where the root is the crazy linker itself, since all // libraries that it loads will depend on it (to ensure their // dlopen/dlsym/dlclose calls are properly wrapped). class SharedLibrary { public: SharedLibrary(); ~SharedLibrary(); size_t load_address() const { return view_.load_address(); } size_t load_size() const { return view_.load_size(); } size_t load_bias() const { return view_.load_bias(); } const ELF::Phdr* phdr() const { return view_.phdr(); } size_t phdr_count() const { return view_.phdr_count(); } const char* base_name() const { return base_name_; } // Load a library (without its dependents) from an ELF file. // Note: This does not apply relocations, nor runs constructors. // |full_path| if the file full path. // |load_address| is the page-aligned load address in memory, or 0. // |file_offset| is the page-aligned file offset. // On failure, return false and set |error| message. // // After this, the caller should load all library dependencies, // Then call Relocate() and CallConstructors() to complete the // operation. bool Load(const char* full_path, size_t load_address, size_t file_offset, Error* error); // Relocate this library, assuming all its dependencies are already // loaded in |lib_list|. On failure, return false and set |error| // message. bool Relocate(LibraryList* lib_list, Vector* dependencies, Error* error); void GetInfo(size_t* load_address, size_t* load_size, size_t* relro_start, size_t* relro_size) { *load_address = view_.load_address(); *load_size = view_.load_size(); *relro_start = relro_start_; *relro_size = relro_size_; } // Returns true iff a given library is mapped to a virtual address range // that contains a given address. bool ContainsAddress(void* address) const { size_t addr = reinterpret_cast(address); return load_address() <= addr && addr <= load_address() + load_size(); } // Call all constructors in the library. void CallConstructors(); // Call all destructors in the library. void CallDestructors(); // Return the ELF symbol entry for a given symbol, if defined by // this library, or NULL otherwise. const ELF::Sym* LookupSymbolEntry(const char* symbol_name); // Find the nearest symbol near a given |address|. On success, return // true and set |*sym_name| to the symbol name, |*sym_addr| to its address // in memory, and |*sym_size| to its size in bytes, if any. bool FindNearestSymbolForAddress(void* address, const char** sym_name, void** sym_addr, size_t* sym_size) { return symbols_.LookupNearestByAddress( address, load_bias(), sym_name, sym_addr, sym_size); } // Return the address of a given |symbol_name| if it is exported // by the library, NULL otherwise. void* FindAddressForSymbol(const char* symbol_name); // Create a new Ashmem region holding a copy of the library's RELRO section, // potentially relocated for a new |load_address|. On success, return true // and sets |*relro_start|, |*relro_size| and |*relro_fd|. Note that the // RELRO start address is adjusted for |load_address|, and that the caller // becomes the owner of |*relro_fd|. On failure, return false and set // |error| message. bool CreateSharedRelro(size_t load_address, size_t* relro_start, size_t* relro_size, int* relro_fd, Error* error); // Try to use a shared relro section from another process. // On success, return true. On failure return false and // sets |error| message. bool UseSharedRelro(size_t relro_start, size_t relro_size, int relro_fd, Error* error); // Look for a symbol named 'JNI_OnLoad' in this library, and if it // exists, call it with |java_vm| as the first parameter. If the // function result is less than |minimum_jni_version|, fail with // a message in |error|. On success, return true, and record // |java_vm| to call 'JNI_OnUnload' at unload time, if present. bool SetJavaVM(void* java_vm, int minimum_jni_version, Error* error); // Call 'JNI_OnUnload()' is necessary, i.e. if there was a succesful call // to SetJavaVM() before. This will pass the same |java_vm| value to the // callback, if it is present in the library. void CallJniOnUnload(); // Helper class to iterate over dependencies in a given SharedLibrary. // Usage: // SharedLibary::DependencyIterator iter(lib); // while (iter.GetNext() { // dependency_name = iter.GetName(); // ... // } class DependencyIterator { public: DependencyIterator(SharedLibrary* lib) : iter_(&lib->view_), symbols_(&lib->symbols_), dep_name_(NULL) {} bool GetNext(); const char* GetName() const { return dep_name_; } private: DependencyIterator(); DependencyIterator(const DependencyIterator&); DependencyIterator& operator=(const DependencyIterator&); ElfView::DynamicIterator iter_; const ElfSymbols* symbols_; const char* dep_name_; }; typedef void (*linker_function_t)(); private: friend class LibraryList; ElfView view_; ElfSymbols symbols_; ELF::Addr relro_start_; ELF::Addr relro_size_; bool relro_used_; SharedLibrary* list_next_; SharedLibrary* list_prev_; unsigned flags_; linker_function_t* preinit_array_; size_t preinit_array_count_; linker_function_t* init_array_; size_t init_array_count_; linker_function_t* fini_array_; size_t fini_array_count_; linker_function_t init_func_; linker_function_t fini_func_; #ifdef __arm__ // ARM EABI section used for stack unwinding. unsigned* arm_exidx_; size_t arm_exidx_count_; #endif link_map_t link_map_; bool has_DT_SYMBOLIC_; void* java_vm_; const char* base_name_; char full_path_[512]; }; } // namespace crazy #endif // CRAZY_LINKER_SHARED_LIBRARY_H