diff --git a/libc/include/elf.h b/libc/include/elf.h index 7a9485aea..7de464e0f 100644 --- a/libc/include/elf.h +++ b/libc/include/elf.h @@ -54,6 +54,35 @@ typedef struct { #define DF_BIND_NOW 0x00000008 #define DF_STATIC_TLS 0x00000010 +#define DF_1_NOW 0x00000001 // Perform complete relocation processing. +#define DF_1_GLOBAL 0x00000002 // implies RTLD_GLOBAL +#define DF_1_GROUP 0x00000004 +#define DF_1_NODELETE 0x00000008 // implies RTLD_NODELETE +#define DF_1_LOADFLTR 0x00000010 +#define DF_1_INITFIRST 0x00000020 +#define DF_1_NOOPEN 0x00000040 // Object can not be used with dlopen(3) +#define DF_1_ORIGIN 0x00000080 +#define DF_1_DIRECT 0x00000100 +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 +#define DF_1_NODEFLIB 0x00000800 +#define DF_1_NODUMP 0x00001000 // Object cannot be dumped with dldump(3) +#define DF_1_CONFALT 0x00002000 +#define DF_1_ENDFILTEE 0x00004000 +#define DF_1_DISPRELDNE 0x00008000 +#define DF_1_DISPRELPND 0x00010000 +#define DF_1_NODIRECT 0x00020000 +#define DF_1_IGNMULDEF 0x00040000 // Internal use +#define DF_1_NOKSYMS 0x00080000 // Internal use +#define DF_1_NOHDR 0x00100000 // Internal use +#define DF_1_EDITED 0x00200000 +#define DF_1_NORELOC 0x00400000 // Internal use +#define DF_1_SYMINTPOSE 0x00800000 +#define DF_1_GLOBAUDIT 0x01000000 +#define DF_1_SINGLETON 0x02000000 +#define DF_1_STUB 0x04000000 +#define DF_1_PIE 0x08000000 + #define DT_BIND_NOW 24 #define DT_INIT_ARRAY 25 #define DT_FINI_ARRAY 26 diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index c02bfb89a..367179d8d 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -147,7 +147,7 @@ int dladdr(const void* addr, Dl_info* info) { // Determine if any symbol in the library contains the specified address. ElfW(Sym)* sym = dladdr_find_symbol(si, addr); if (sym != nullptr) { - info->dli_sname = si->strtab + sym->st_name; + info->dli_sname = si->get_string(sym->st_name); info->dli_saddr = reinterpret_cast(si->resolve_symbol_address(sym)); } @@ -245,6 +245,7 @@ soinfo* get_libdl_info() { __libdl_info.bucket = g_libdl_buckets; __libdl_info.chain = g_libdl_chains; __libdl_info.ref_count = 1; + __libdl_info.strtab_size = sizeof(ANDROID_LIBDL_STRTAB); } return &__libdl_info; diff --git a/linker/linker.cpp b/linker/linker.cpp index 30731090c..9e26cf840 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -417,14 +417,13 @@ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) { ElfW(Sym)* symtab = si->symtab; - const char* strtab = si->strtab; TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd", name, si->name, reinterpret_cast(si->base), hash, hash % si->nbucket); for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) { ElfW(Sym)* s = symtab + n; - if (strcmp(strtab + s->st_name, name)) continue; + if (strcmp(si->get_string(s->st_name), name)) continue; // only concern ourselves with global and weak symbol definitions switch (ELF_ST_BIND(s->st_info)) { @@ -776,7 +775,7 @@ template static void for_each_dt_needed(const soinfo* si, F action) { for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { if (d->d_tag == DT_NEEDED) { - action(si->strtab + d->d_un.d_val); + action(si->get_string(d->d_un.d_val)); } } } @@ -1103,7 +1102,7 @@ int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { soinfo* lsi = nullptr; if (sym != 0) { - sym_name = reinterpret_cast(strtab + symtab[sym].st_name); + sym_name = get_string(symtab[sym].st_name); s = soinfo_do_lookup(this, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... @@ -1381,7 +1380,7 @@ int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { soinfo* lsi = nullptr; if (sym != 0) { - sym_name = reinterpret_cast(strtab + symtab[sym].st_name); + sym_name = get_string(symtab[sym].st_name); s = soinfo_do_lookup(this, sym_name, &lsi); if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... @@ -1599,7 +1598,7 @@ static bool mips_relocate_got(soinfo* si) { got = si->plt_got + local_gotno; for (size_t g = gotsym; g < symtabno; g++, sym++, got++) { // This is an undefined reference... try to locate it. - const char* sym_name = si->strtab + sym->st_name; + const char* sym_name = si->get_string(sym->st_name); soinfo* lsi = nullptr; ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); if (s == nullptr) { @@ -1801,6 +1800,14 @@ ElfW(Addr) soinfo::resolve_symbol_address(ElfW(Sym)* s) { return static_cast(s->st_value + load_bias); } +const char* soinfo::get_string(ElfW(Word) index) const { + if (has_min_version(1) && (index >= strtab_size)) { + __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d", name, strtab_size, index); + } + + return strtab + index; +} + /* Force any of the closed stdin, stdout and stderr to be associated with /dev/null. */ static int nullify_closed_stdio() { @@ -1909,6 +1916,9 @@ bool soinfo::PrelinkImage() { case DT_STRTAB: strtab = reinterpret_cast(load_bias + d->d_un.d_ptr); break; + case DT_STRSZ: + strtab_size = d->d_un.d_val; + break; case DT_SYMTAB: symtab = reinterpret_cast(load_bias + d->d_un.d_ptr); break; @@ -2062,6 +2072,16 @@ bool soinfo::PrelinkImage() { has_DT_SYMBOLIC = true; } break; + case DT_FLAGS_1: + if ((d->d_un.d_val & DF_1_GLOBAL) != 0) { + rtld_flags |= RTLD_GLOBAL; + } + // TODO: Implement other flags + + if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL)) != 0) { + DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast(d->d_un.d_val)); + } + break; #if defined(__mips__) case DT_STRSZ: break; @@ -2093,7 +2113,7 @@ bool soinfo::PrelinkImage() { default: if (!relocating_linker) { - DEBUG("%s: unused DT entry: type %p arg %p", name, + DL_WARN("%s: unused DT entry: type %p arg %p", name, reinterpret_cast(d->d_tag), reinterpret_cast(d->d_un.d_val)); } break; diff --git a/linker/linker.h b/linker/linker.h index ef2fbcd6c..6329efda6 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -136,7 +136,9 @@ struct soinfo { soinfo* next; unsigned flags; + private: const char* strtab; + public: ElfW(Sym)* symtab; size_t nbucket; @@ -221,7 +223,9 @@ struct soinfo { ElfW(Addr) resolve_symbol_address(ElfW(Sym)* s); - bool inline has_min_version(uint32_t min_version) { + const char* get_string(ElfW(Word) index) const; + + bool inline has_min_version(uint32_t min_version) const { return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; } private: @@ -249,6 +253,9 @@ struct soinfo { // version >= 1 off64_t file_offset; int rtld_flags; + size_t strtab_size; + + friend soinfo* get_libdl_info(); }; extern soinfo* get_libdl_info();