Merge "Move frameworks/compile/linkloader into frameworks/rs." into jb-mr2-dev
diff --git a/Android.mk b/Android.mk
index 5d5dccb..1c71962 100644
--- a/Android.mk
+++ b/Android.mk
@@ -245,5 +245,207 @@
include $(BUILD_HOST_STATIC_LIBRARY)
+
+LLVM_ROOT_PATH := external/llvm
+
+#=============================================================================
+# android librsloader for libbcc (Device)
+#-----------------------------------------------------------------------------
+
+rsloader_SRC_FILES := \
+ driver/linkloader/android/librsloader.cpp \
+ driver/linkloader/lib/ELFHeader.cpp \
+ driver/linkloader/lib/ELFSymbol.cpp \
+ driver/linkloader/lib/ELFSectionHeader.cpp \
+ driver/linkloader/lib/ELFTypes.cpp \
+ driver/linkloader/lib/GOT.cpp \
+ driver/linkloader/lib/MemChunk.cpp \
+ driver/linkloader/lib/StubLayout.cpp \
+ driver/linkloader/utils/helper.cpp \
+ driver/linkloader/utils/raw_ostream.cpp \
+ driver/linkloader/utils/rsl_assert.cpp
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := librsloader
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(rsloader_SRC_FILES)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_CFLAGS += $(rs_base_CFLAGS)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/driver/linkloader \
+ $(LOCAL_PATH)/driver/linkloader/include \
+ $(LOCAL_C_INCLUDES)
+
+include $(LLVM_ROOT_PATH)/llvm-device-build.mk
+include $(BUILD_STATIC_LIBRARY)
+
+
+#=============================================================================
+# android librsloader for libbcc (Host)
+#-----------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := librsloader
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(rsloader_SRC_FILES)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_CFLAGS += $(rs_base_CFLAGS)
+LOCAL_CFLAGS += -D__HOST__
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/driver/linkloader \
+ $(LOCAL_PATH)/driver/linkloader/include \
+ $(LOCAL_C_INCLUDES)
+
+include $(LLVM_ROOT_PATH)/llvm-host-build.mk
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+#=============================================================================
+# librsloader-test (Device)
+#-----------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := test-librsloader
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport
+
+LOCAL_STATIC_LIBRARIES := \
+ librsloader \
+ libcutils \
+ libLLVMSupport
+
+LOCAL_SRC_FILES := \
+ driver/linkloader/android/test-librsloader.c
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_CFLAGS += $(rs_base_CFLAGS)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/driver/linkloader \
+ $(LOCAL_PATH)/driver/linkloader/include
+
+include $(LLVM_ROOT_PATH)/llvm-device-build.mk
+include $(BUILD_EXECUTABLE)
+
+
+#=============================================================================
+# librsloader-test (Host)
+#-----------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := test-librsloader
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_LDLIBS := \
+ -lpthread \
+ -ldl
+
+LOCAL_STATIC_LIBRARIES := \
+ librsloader \
+ libcutils \
+ libLLVMSupport
+
+LOCAL_SRC_FILES := \
+ driver/linkloader/android/test-librsloader.c
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_CFLAGS += $(rs_base_CFLAGS)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/driver/linkloader \
+ $(LOCAL_PATH)/driver/linkloader/include
+
+include $(LLVM_ROOT_PATH)/llvm-host-build.mk
+include $(BUILD_HOST_EXECUTABLE)
+
+
+#=============================================================================
+# rsloader
+#-----------------------------------------------------------------------------
+
+ifdef BUILD_RSLOADER_TOOL
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := rsloader
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport
+
+LOCAL_STATIC_LIBRARIES := \
+ libLLVMSupport
+
+LOCAL_SRC_FILES := \
+ driver/linkloader/lib/ELFHeader.cpp \
+ driver/linkloader/lib/ELFSymbol.cpp \
+ driver/linkloader/lib/ELFSectionHeader.cpp \
+ driver/linkloader/lib/ELFTypes.cpp \
+ driver/linkloader/lib/StubLayout.cpp \
+ driver/linkloader/utils/raw_ostream.cpp \
+ driver/linkloader/utils/rsl_assert.cpp \
+ driver/linkloader/utils/helper.cpp \
+ driver/linkloader/main.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/driver/linkloader \
+ $(LOCAL_PATH)/driver/linkloader/include \
+ $(LOCAL_C_INCLUDES)
+
+include $(LLVM_ROOT_PATH)/llvm-device-build.mk
+include $(BUILD_EXECUTABLE)
+endif
+
+
+#=============================================================================
+# stub-layout-unit-test
+#-----------------------------------------------------------------------------
+
+ifdef BUILD_STUB_LAYOUT_TEST
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := stub-layout-unit-test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport
+
+LOCAL_SRC_FILES := \
+ driver/linkloader/lib/StubLayout.cpp \
+ driver/linkloader/utils/raw_ostream.cpp \
+ driver/linkloader/utils/helper.cpp \
+ driver/linkloader/tests/stub-test.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/driver/linkloader \
+ $(LOCAL_PATH)/driver/linkloader/include \
+ $(LOCAL_C_INCLUDES)
+
+include $(LLVM_ROOT_PATH)/llvm-device-build.mk
+include $(BUILD_EXECUTABLE)
+endif
+
+
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/driver/linkloader/android/librsloader.cpp b/driver/linkloader/android/librsloader.cpp
new file mode 100644
index 0000000..200006f
--- /dev/null
+++ b/driver/linkloader/android/librsloader.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "librsloader.h"
+
+#include "ELFObject.h"
+#include "ELFSectionSymTab.h"
+#include "ELFSymbol.h"
+
+#include "utils/serialize.h"
+
+#define LOG_TAG "bcc"
+#include "cutils/log.h"
+
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/Support/ELF.h>
+
+static inline RSExecRef wrap(ELFObject<32> *object) {
+ return reinterpret_cast<RSExecRef>(object);
+}
+
+static inline ELFObject<32> *unwrap(RSExecRef object) {
+ return reinterpret_cast<ELFObject<32> *>(object);
+}
+
+extern "C" RSExecRef rsloaderCreateExec(unsigned char const *buf,
+ size_t buf_size,
+ RSFindSymbolFn find_symbol,
+ void *find_symbol_context) {
+ RSExecRef object = rsloaderLoadExecutable(buf, buf_size);
+ if (!object) {
+ return NULL;
+ }
+
+ if (!rsloaderRelocateExecutable(object, find_symbol, find_symbol_context)) {
+ rsloaderDisposeExec(object);
+ return NULL;
+ }
+
+ return object;
+}
+
+extern "C" RSExecRef rsloaderLoadExecutable(unsigned char const *buf,
+ size_t buf_size) {
+ ArchiveReaderLE AR(buf, buf_size);
+
+ llvm::OwningPtr<ELFObject<32> > object(ELFObject<32>::read(AR));
+ if (!object) {
+ ALOGE("Unable to load the ELF object.");
+ return NULL;
+ }
+
+ return wrap(object.take());
+}
+
+extern "C" int rsloaderRelocateExecutable(RSExecRef object_,
+ RSFindSymbolFn find_symbol,
+ void *find_symbol_context) {
+ ELFObject<32>* object = unwrap(object_);
+
+ object->relocate(find_symbol, find_symbol_context);
+ return (object->getMissingSymbols() == 0);
+}
+
+extern "C" void rsloaderUpdateSectionHeaders(RSExecRef object_,
+ unsigned char *buf) {
+ ELFObject<32> *object = unwrap(object_);
+
+ // Remap the section header addresses to match the loaded code
+ llvm::ELF::Elf32_Ehdr* header = reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(buf);
+
+ llvm::ELF::Elf32_Shdr* shtab =
+ reinterpret_cast<llvm::ELF::Elf32_Shdr*>(buf + header->e_shoff);
+
+ for (int i = 0; i < header->e_shnum; i++) {
+ if (shtab[i].sh_flags & SHF_ALLOC) {
+ ELFSectionBits<32>* bits =
+ static_cast<ELFSectionBits<32>*>(object->getSectionByIndex(i));
+ if (bits) {
+ const unsigned char* addr = bits->getBuffer();
+ shtab[i].sh_addr = reinterpret_cast<llvm::ELF::Elf32_Addr>(addr);
+ }
+ }
+ }
+}
+
+extern "C" void rsloaderDisposeExec(RSExecRef object) {
+ delete unwrap(object);
+}
+
+extern "C" void *rsloaderGetSymbolAddress(RSExecRef object_,
+ char const *name) {
+ ELFObject<32> *object = unwrap(object_);
+
+ ELFSectionSymTab<32> *symtab =
+ static_cast<ELFSectionSymTab<32> *>(object->getSectionByName(".symtab"));
+
+ if (!symtab) {
+ return NULL;
+ }
+
+ ELFSymbol<32> *symbol = symtab->getByName(name);
+
+ if (!symbol) {
+ ALOGV("Symbol not found: %s\n", name);
+ return NULL;
+ }
+
+ int machine = object->getHeader()->getMachine();
+
+ return symbol->getAddress(machine, false);
+}
+
+extern "C" size_t rsloaderGetSymbolSize(RSExecRef object_, char const *name) {
+ ELFObject<32> *object = unwrap(object_);
+
+ ELFSectionSymTab<32> *symtab =
+ static_cast<ELFSectionSymTab<32> *>(object->getSectionByName(".symtab"));
+
+ if (!symtab) {
+ return 0;
+ }
+
+ ELFSymbol<32> *symbol = symtab->getByName(name);
+
+ if (!symbol) {
+ ALOGV("Symbol not found: %s\n", name);
+ return 0;
+ }
+
+ return (size_t)symbol->getSize();
+}
+
+extern "C" size_t rsloaderGetFuncCount(RSExecRef object) {
+ ELFSectionSymTab<32> *symtab = static_cast<ELFSectionSymTab<32> *>(
+ unwrap(object)->getSectionByName(".symtab"));
+
+ if (!symtab) {
+ return 0;
+ }
+
+ return symtab->getFuncCount();
+}
+
+extern "C" void rsloaderGetFuncNameList(RSExecRef object,
+ size_t size,
+ char const **list) {
+ ELFSectionSymTab<32> *symtab = static_cast<ELFSectionSymTab<32> *>(
+ unwrap(object)->getSectionByName(".symtab"));
+
+ if (symtab) {
+ symtab->getFuncNameList(size, list);
+ }
+}
diff --git a/driver/linkloader/android/librsloader.h b/driver/linkloader/android/librsloader.h
new file mode 100644
index 0000000..ab8361a
--- /dev/null
+++ b/driver/linkloader/android/librsloader.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBRSLOADER_H
+#define LIBRSLOADER_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct RSExecOpaque;
+typedef struct RSExecOpaque *RSExecRef;
+typedef void *(*RSFindSymbolFn)(void *, char const *);
+
+RSExecRef rsloaderCreateExec(unsigned char const *buf,
+ size_t buf_size,
+ RSFindSymbolFn find_symbol,
+ void *find_symbol_context);
+
+RSExecRef rsloaderLoadExecutable(unsigned char const *buf,
+ size_t buf_size);
+
+int rsloaderRelocateExecutable(RSExecRef object,
+ RSFindSymbolFn find_symbol,
+ void *find_symbol_context);
+
+void rsloaderUpdateSectionHeaders(RSExecRef object, unsigned char *buf);
+
+void rsloaderDisposeExec(RSExecRef object);
+
+void *rsloaderGetSymbolAddress(RSExecRef object, char const *name);
+
+size_t rsloaderGetSymbolSize(RSExecRef object, char const *name);
+
+size_t rsloaderGetFuncCount(RSExecRef object);
+
+void rsloaderGetFuncNameList(RSExecRef object, size_t size, char const **list);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LIBRSLOADER_H */
diff --git a/driver/linkloader/android/test-librsloader.c b/driver/linkloader/android/test-librsloader.c
new file mode 100644
index 0000000..3c9ac2d
--- /dev/null
+++ b/driver/linkloader/android/test-librsloader.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "librsloader.h"
+#include "utils/rsl_assert.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+struct func_entry_t {
+ char const *name;
+ size_t name_len;
+ void *addr;
+};
+
+void *find_sym(void *context, char const *name) {
+ static struct func_entry_t const tab[] = {
+#define DEF(NAME, ADDR) \
+ { NAME, sizeof(NAME) - 1, (void *)(&(ADDR)) },
+
+ DEF("printf", printf)
+ DEF("scanf", scanf)
+ DEF("__isoc99_scanf", scanf)
+ DEF("rand", rand)
+ DEF("time", time)
+ DEF("srand", srand)
+#undef DEF
+ };
+
+ static size_t const tab_size = sizeof(tab) / sizeof(struct func_entry_t);
+
+ // Note: Since our table is small, we are using trivial O(n) searching
+ // function. For bigger table, it will be better to use binary
+ // search or hash function.
+ size_t i;
+ size_t name_len = strlen(name);
+ for (i = 0; i < tab_size; ++i) {
+ if (name_len == tab[i].name_len && strcmp(name, tab[i].name) == 0) {
+ return tab[i].addr;
+ }
+ }
+
+ rsl_assert(0 && "Can't find symbol.");
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ fprintf(stderr, "USAGE: %s [ELF] [ARGS]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ int fd = open(argv[1], O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: Unable to open the file: %s\n", argv[1]);
+ exit(EXIT_FAILURE);
+ }
+
+ struct stat sb;
+ if (fstat(fd, &sb) != 0) {
+ fprintf(stderr, "ERROR: Unable to stat the file: %s\n", argv[1]);
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+
+ unsigned char const *image = (unsigned char const *)
+ mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ if (image == MAP_FAILED) {
+ fprintf(stderr, "ERROR: Unable to mmap the file: %s\n", argv[1]);
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+
+ RSExecRef object = rsloaderCreateExec(image, sb.st_size, find_sym, 0);
+ if (!object) {
+ fprintf(stderr, "ERROR: Unable to load elf object.\n");
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+
+ int (*main_stub)(int, char **) =
+ (int (*)(int, char **))rsloaderGetSymbolAddress(object, "main");
+
+ int ret = main_stub(argc - 1, argv + 1);
+ printf("============================================================\n");
+ printf("ELF object finished with code: %d\n", ret);
+ fflush(stdout);
+
+ rsloaderDisposeExec(object);
+
+ close(fd);
+
+ return EXIT_SUCCESS;
+}
diff --git a/driver/linkloader/include/ELF.h b/driver/linkloader/include/ELF.h
new file mode 100644
index 0000000..6205b98
--- /dev/null
+++ b/driver/linkloader/include/ELF.h
@@ -0,0 +1,19 @@
+#ifndef ELF_H
+#define ELF_H
+
+#include <llvm/Support/ELF.h>
+// FIXME: Can't using namespace in header file!
+using namespace llvm::ELF;
+
+// These definitions are not defined in include/llvm/Support/ELF.h.
+// So we define them here.
+
+#ifndef ET_LOOS
+#define ET_LOOS 0xfe00
+#endif
+
+#ifndef ET_HIOS
+#define ET_HIOS 0xfeff
+#endif
+
+#endif // ELF_H
diff --git a/driver/linkloader/include/ELFHeader.h b/driver/linkloader/include/ELFHeader.h
new file mode 100644
index 0000000..98fa920
--- /dev/null
+++ b/driver/linkloader/include/ELFHeader.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_HEADER_H
+#define ELF_HEADER_H
+
+#include "ELFTypes.h"
+#include "ELF.h"
+
+#include <llvm/ADT/OwningPtr.h>
+
+#include <string.h>
+
+class ELFHeaderHelperMixin {
+protected:
+ static char const *getClassStr(int clazz);
+ static char const *getEndiannessStr(int endianness);
+ static char const *getOSABIStr(int abi);
+ static char const *getObjectTypeStr(uint16_t type);
+ static char const *getMachineStr(uint16_t machine);
+ static char const *getVersionStr(uint32_t version);
+};
+
+template <unsigned Bitwidth>
+class ELFHeader : private ELFHeaderHelperMixin {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+protected:
+ byte_t e_ident[EI_NIDENT];
+ half_t e_type;
+ half_t e_machine;
+ word_t e_version;
+ addr_t e_entry;
+ offset_t e_phoff;
+ offset_t e_shoff;
+ word_t e_flags;
+ half_t e_ehsize;
+ half_t e_phentsize;
+ half_t e_phnum;
+ half_t e_shentsize;
+ half_t e_shnum;
+ half_t e_shstrndx;
+
+protected:
+ ELFHeader() { }
+
+public:
+ byte_t getClass() const {
+ return e_ident[EI_CLASS];
+ }
+
+ byte_t getEndianness() const {
+ return e_ident[EI_DATA];
+ }
+
+ byte_t getVersionFromIdent() const {
+ return e_ident[EI_VERSION];
+ }
+
+ byte_t getOSABI() const {
+ return e_ident[EI_OSABI];
+ }
+
+ byte_t getABIVersion() const {
+ return e_ident[EI_ABIVERSION];
+ }
+
+ bool is32bit() const {
+ return e_ident[EI_CLASS] == ELFCLASS32;
+ }
+
+ bool is64bit() const {
+ return e_ident[EI_CLASS] == ELFCLASS64;
+ }
+
+ bool isBigEndian() const {
+ return e_ident[EI_DATA] == ELFDATA2MSB;
+ }
+
+ bool isLittleEndian() const {
+ return e_ident[EI_DATA] == ELFDATA2LSB;
+ }
+
+ half_t getObjectType() const {
+ return e_type;
+ }
+
+ half_t getMachine() const {
+ return e_machine;
+ }
+
+ word_t getVersion() const {
+ return e_version;
+ }
+
+ addr_t getEntryAddress() const {
+ return e_entry;
+ }
+
+ offset_t getProgramHeaderTableOffset() const {
+ return e_phoff;
+ }
+
+ offset_t getSectionHeaderTableOffset() const {
+ return e_shoff;
+ }
+
+ word_t getFlags() const {
+ return e_flags;
+ }
+
+ half_t getELFHeaderSize() const {
+ return e_ehsize;
+ }
+
+ half_t getProgramHeaderEntrySize() const {
+ return e_phentsize;
+ }
+
+ half_t getProgramHeaderNum() const {
+ return e_phnum;
+ }
+
+ half_t getSectionHeaderEntrySize() const {
+ return e_shentsize;
+ }
+
+ half_t getSectionHeaderNum() const {
+ return e_shnum;
+ }
+
+ half_t getStringSectionIndex() const {
+ return e_shstrndx;
+ }
+
+ template <typename Archiver>
+ static ELFHeader *read(Archiver &AR) {
+ if (!AR) {
+ // Archiver is in bad state before calling read function.
+ // Return NULL and do nothing.
+ return 0;
+ }
+
+ llvm::OwningPtr<ELFHeader> header(new ELFHeader());
+ if (!header->serialize(AR)) {
+ // Unable to read the structure. Return NULL.
+ return 0;
+ }
+
+ if (!header->isValid()) {
+ // Header read from archiver is not valid. Return NULL.
+ return 0;
+ }
+
+ return header.take();
+ }
+
+ void print();
+
+ bool isValid() const {
+ return (isValidELFIdent() && isCompatibleHeaderSize());
+ }
+
+private:
+ template <typename Archiver>
+ bool serialize(Archiver &AR) {
+ AR.prologue(TypeTraits<ELFHeaderTy>::size);
+
+ AR & e_ident;
+ AR & e_type;
+ AR & e_machine;
+ AR & e_version;
+ AR & e_entry;
+ AR & e_phoff;
+ AR & e_shoff;
+ AR & e_flags;
+ AR & e_ehsize;
+ AR & e_phentsize;
+ AR & e_phnum;
+ AR & e_shentsize;
+ AR & e_shnum;
+ AR & e_shstrndx;
+
+ AR.epilogue(TypeTraits<ELFHeaderTy>::size);
+ return AR;
+ }
+
+ bool isValidMagicWord() const {
+ return (memcmp(e_ident, "\x7f" "ELF", 4) == 0);
+ }
+
+ bool isValidClass() const {
+ return ((Bitwidth == 32 && is32bit()) ||
+ (Bitwidth == 64 && is64bit()));
+ }
+
+ bool isValidEndianness() const {
+ return (isBigEndian() || isLittleEndian());
+ }
+
+ bool isValidHeaderVersion() const {
+ return (getVersion() == EV_CURRENT);
+ }
+
+ bool isUnusedZeroedPadding() const {
+ for (size_t i = EI_PAD; i < EI_NIDENT; ++i) {
+ if (e_ident[i] != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool isValidELFIdent() const {
+ return (isValidMagicWord() &&
+ isValidClass() &&
+ isValidEndianness() &&
+ isValidHeaderVersion() &&
+ isUnusedZeroedPadding());
+ }
+
+ bool isCompatibleHeaderSize() const {
+ return (
+ (e_ehsize == TypeTraits<ELFHeaderTy>::size) &&
+ (e_phnum == 0 || e_phentsize == TypeTraits<ELFProgramHeaderTy>::size) &&
+ (e_shnum == 0 || e_shentsize == TypeTraits<ELFSectionHeaderTy>::size));
+ }
+};
+
+#include "impl/ELFHeader.hxx"
+
+#endif // ELF_HEADER_H
diff --git a/driver/linkloader/include/ELFObject.h b/driver/linkloader/include/ELFObject.h
new file mode 100644
index 0000000..d715d51
--- /dev/null
+++ b/driver/linkloader/include/ELFObject.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_OBJECT_H
+#define ELF_OBJECT_H
+
+#include "ELFTypes.h"
+#include "MemChunk.h"
+
+#include "utils/rsl_assert.h"
+
+#include <llvm/ADT/OwningPtr.h>
+
+#include <string>
+#include <vector>
+
+template <unsigned Bitwidth>
+class ELFObject {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+private:
+ llvm::OwningPtr<ELFHeaderTy> header;
+ llvm::OwningPtr<ELFSectionHeaderTableTy> shtab;
+ std::vector<ELFSectionTy *> stab;
+
+ MemChunk SHNCommonData;
+ unsigned char *SHNCommonDataPtr;
+ size_t SHNCommonDataFreeSize;
+
+ bool missingSymbols;
+
+ // TODO: Need refactor!
+ bool initSHNCommonDataSize(size_t SHNCommonDataSize) {
+ rsl_assert(!SHNCommonDataPtr && "Can't init twice.");
+ if (!SHNCommonData.allocate(SHNCommonDataSize)) {
+ return false;
+ }
+
+ SHNCommonDataPtr = SHNCommonData.getBuffer();
+ SHNCommonDataFreeSize = SHNCommonDataSize;
+ return true;
+ }
+
+private:
+ ELFObject() : SHNCommonDataPtr(NULL), missingSymbols(false) { }
+
+public:
+ template <typename Archiver>
+ static ELFObject *read(Archiver &AR);
+
+ ELFHeaderTy const *getHeader() const {
+ return header.get();
+ }
+
+ ELFSectionHeaderTableTy const *getSectionHeaderTable() const {
+ return shtab.get();
+ }
+
+ char const *getSectionName(size_t i) const;
+ ELFSectionTy const *getSectionByIndex(size_t i) const;
+ ELFSectionTy *getSectionByIndex(size_t i);
+ ELFSectionTy const *getSectionByName(std::string const &str) const;
+ ELFSectionTy *getSectionByName(std::string const &str);
+
+ inline bool getMissingSymbols() const {
+ return missingSymbols;
+ }
+
+ void *allocateSHNCommonData(size_t size, size_t align = 1) {
+ rsl_assert(size > 0 && align != 0);
+
+ rsl_assert(SHNCommonDataPtr && "Must init common data size before use!");
+
+ // Ensure alignment
+ size_t rem = ((uintptr_t)SHNCommonDataPtr) % align;
+ if (rem != 0) {
+ SHNCommonDataPtr += align - rem;
+ SHNCommonDataFreeSize -= align - rem;
+ }
+
+ // Ensure the free size is sufficient
+ if (SHNCommonDataFreeSize < size) {
+ return NULL;
+ }
+
+ // Allcoate
+ void *result = SHNCommonDataPtr;
+ SHNCommonDataPtr += size;
+ SHNCommonDataFreeSize -= size;
+
+ return result;
+ }
+
+ void relocate(void *(*find_sym)(void *context, char const *name),
+ void *context);
+
+ void print() const;
+
+ ~ELFObject() {
+ for (size_t i = 0; i < stab.size(); ++i) {
+ // Delete will check the pointer is nullptr or not by himself.
+ delete stab[i];
+ }
+ }
+
+private:
+ void relocateARM(void *(*find_sym)(void *context, char const *name),
+ void *context,
+ ELFSectionRelTableTy *reltab,
+ ELFSectionProgBitsTy *text);
+
+ void relocateX86_32(void *(*find_sym)(void *context, char const *name),
+ void *context,
+ ELFSectionRelTableTy *reltab,
+ ELFSectionProgBitsTy *text);
+
+ void relocateX86_64(void *(*find_sym)(void *context, char const *name),
+ void *context,
+ ELFSectionRelTableTy *reltab,
+ ELFSectionProgBitsTy *text);
+
+ void relocateMIPS(void *(*find_sym)(void *context, char const *name),
+ void *context,
+ ELFSectionRelTableTy *reltab,
+ ELFSectionProgBitsTy *text);
+};
+
+#include "impl/ELFObject.hxx"
+
+#endif // ELF_OBJECT_H
diff --git a/driver/linkloader/include/ELFReloc.h b/driver/linkloader/include/ELFReloc.h
new file mode 100644
index 0000000..c6bf759
--- /dev/null
+++ b/driver/linkloader/include/ELFReloc.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_RELOC_H
+#define ELF_RELOC_H
+
+#include "ELFTypes.h"
+#include "utils/rsl_assert.h"
+
+#include <llvm/ADT/OwningPtr.h>
+#include <string>
+#include <stdint.h>
+
+template <unsigned Bitwidth>
+class ELFReloc_CRTP {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+protected:
+ size_t index;
+
+ addr_t r_offset;
+ relinfo_t r_info;
+ addend_t r_addend;
+
+protected:
+ ELFReloc_CRTP() : index(0), r_offset(0), r_addend(0) { }
+ ~ELFReloc_CRTP() { }
+
+public:
+ size_t getIndex() const {
+ return index;
+ }
+
+ addr_t getOffset() const {
+ return r_offset;
+ }
+
+ addend_t getAddend() const {
+ return r_addend;
+ }
+
+ bool isValid() const {
+ // FIXME: Should check the correctness of the relocation entite.
+ return true;
+ }
+
+ template <typename Archiver>
+ static ELFRelocTy *readRel(Archiver &AR, size_t index);
+
+ template <typename Archiver>
+ static ELFRelocTy *readRela(Archiver &AR, size_t index);
+
+ void print(bool shouldPrintHeader = false) const;
+
+private:
+ ELFRelocTy *concrete() {
+ return static_cast<ELFRelocTy *>(this);
+ }
+
+ ELFRelocTy const *concrete() const {
+ return static_cast<ELFRelocTy const *>(this);
+ }
+
+ template <typename Archiver>
+ bool serializeRel(Archiver &AR) {
+ rsl_assert(r_addend == 0 && "r_addend should be zero before serialization.");
+
+ AR.prologue(TypeTraits<ELFRelocRelTy>::size);
+
+ AR & r_offset;
+ AR & r_info;
+
+ AR.epilogue(TypeTraits<ELFRelocRelTy>::size);
+ return AR;
+ }
+
+ template <typename Archiver>
+ bool serializeRela(Archiver &AR) {
+ AR.prologue(TypeTraits<ELFRelocRelaTy>::size);
+
+ AR & r_offset;
+ AR & r_info;
+ AR & r_addend;
+
+ AR.epilogue(TypeTraits<ELFRelocRelaTy>::size);
+ return AR;
+ }
+
+};
+
+template <>
+class ELFReloc<32> : public ELFReloc_CRTP<32> {
+ friend class ELFReloc_CRTP<32>;
+
+private:
+ ELFReloc() {
+ }
+
+public:
+ word_t getSymTabIndex() const {
+#define ELF32_R_SYM(i) ((i)>>8)
+ return ELF32_R_SYM(this->r_info);
+#undef ELF32_R_SYM
+ }
+
+ word_t getType() const {
+#define ELF32_R_TYPE(i) ((unsigned char)(i))
+ return ELF32_R_TYPE(this->r_info);
+#undef ELF32_R_TYPE
+ }
+
+};
+
+template <>
+class ELFReloc<64> : public ELFReloc_CRTP<64> {
+ friend class ELFReloc_CRTP<64>;
+
+private:
+ ELFReloc() {
+ }
+
+public:
+ xword_t getSymTabIndex() const {
+#define ELF64_R_SYM(i) ((i)>>32)
+ return ELF64_R_SYM(this->r_info);
+#undef ELF64_R_SYM
+ }
+
+ xword_t getType() const {
+#define ELF64_R_TYPE(i) ((i)&0xffffffffL)
+ return ELF64_R_TYPE(this->r_info);
+#undef ELF64_R_TYPE
+ }
+};
+
+#include "impl/ELFReloc.hxx"
+
+#endif // ELF_RELOC_H
diff --git a/driver/linkloader/include/ELFSection.h b/driver/linkloader/include/ELFSection.h
new file mode 100644
index 0000000..74c4c13
--- /dev/null
+++ b/driver/linkloader/include/ELFSection.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_H
+#define ELF_SECTION_H
+
+#include "ELFTypes.h"
+#include <llvm/ADT/OwningPtr.h>
+
+template <unsigned Bitwidth>
+class ELFSection {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+protected:
+ ELFSection() { }
+
+public:
+ virtual ~ELFSection() { }
+
+ virtual void print() const = 0;
+
+ template <typename Archiver>
+ static ELFSection *read(Archiver &AR, ELFObjectTy *,
+ ELFSectionHeaderTy const *);
+};
+
+#include "impl/ELFSection.hxx"
+
+#endif // ELF_SECTION_H
diff --git a/driver/linkloader/include/ELFSectionBits.h b/driver/linkloader/include/ELFSectionBits.h
new file mode 100644
index 0000000..2d80c1a
--- /dev/null
+++ b/driver/linkloader/include/ELFSectionBits.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_BITS_H
+#define ELF_SECTION_BITS_H
+
+#include "ELFTypes.h"
+#include "ELFSection.h"
+#include "MemChunk.h"
+
+#include <llvm/ADT/OwningPtr.h>
+
+template <unsigned Bitwidth>
+class ELFSectionBits : public ELFSection<Bitwidth> {
+protected:
+ ELFSectionHeader<Bitwidth> const *sh;
+ MemChunk chunk;
+
+protected:
+ ELFSectionBits() : sh(NULL) { }
+
+public:
+ virtual void print() const;
+
+ bool protect();
+
+ unsigned char const *getBuffer() const {
+ return chunk.getBuffer();
+ }
+
+ unsigned char *getBuffer() {
+ return chunk.getBuffer();
+ }
+
+ unsigned char &operator[](size_t index) {
+ return chunk[index];
+ }
+
+ unsigned char const &operator[](size_t index) const {
+ return chunk[index];
+ }
+
+ size_t size() const {
+ return chunk.size();
+ }
+
+};
+
+#include "impl/ELFSectionBits.hxx"
+
+#endif // ELF_SECTION_BITS_H
diff --git a/driver/linkloader/include/ELFSectionHeader.h b/driver/linkloader/include/ELFSectionHeader.h
new file mode 100644
index 0000000..7871315
--- /dev/null
+++ b/driver/linkloader/include/ELFSectionHeader.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_HEADER_H
+#define ELF_SECTION_HEADER_H
+
+#include "ELFTypes.h"
+
+#include <llvm/ADT/OwningPtr.h>
+#include <stdint.h>
+
+class ELFSectionHeaderHelperMixin {
+protected:
+ static char const *getSectionTypeStr(uint32_t type);
+};
+
+template <unsigned Bitwidth>
+class ELFSectionHeader_CRTP : private ELFSectionHeaderHelperMixin {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+protected:
+ ELFObjectTy const *owner;
+
+ size_t index;
+
+ word_t sh_name;
+ word_t sh_type;
+ addr_t sh_addr;
+ offset_t sh_offset;
+ word_t sh_link;
+ word_t sh_info;
+
+protected:
+ ELFSectionHeader_CRTP() { }
+ ~ELFSectionHeader_CRTP() { }
+
+public:
+ size_t getIndex() const {
+ return index;
+ }
+
+ word_t getNameIndex() const {
+ return sh_name;
+ }
+
+ char const *getName() const;
+
+ word_t getType() const {
+ return sh_type;
+ }
+
+ addr_t getAddress() const {
+ return sh_addr;
+ }
+
+ offset_t getOffset() const {
+ return sh_offset;
+ }
+
+ word_t getLink() const {
+ return sh_link;
+ }
+
+ word_t getExtraInfo() const {
+ return sh_info;
+ }
+
+ bool isValid() const {
+ // FIXME: Should check the correctness of the section header.
+ return true;
+ }
+
+ template <typename Archiver>
+ static ELFSectionHeaderTy *
+ read(Archiver &AR, ELFObjectTy const *owner, size_t index = 0);
+
+ void print(bool shouldPrintHeader = false) const;
+
+private:
+ ELFSectionHeaderTy *concrete() {
+ return static_cast<ELFSectionHeaderTy *>(this);
+ }
+
+ ELFSectionHeaderTy const *concrete() const {
+ return static_cast<ELFSectionHeaderTy const *>(this);
+ }
+};
+
+
+#include "impl/ELFSectionHeader.hxx"
+
+template <>
+class ELFSectionHeader<32> : public ELFSectionHeader_CRTP<32> {
+ friend class ELFSectionHeader_CRTP<32>;
+
+private:
+ word_t sh_flags;
+ word_t sh_size;
+ word_t sh_addralign;
+ word_t sh_entsize;
+
+private:
+ ELFSectionHeader() {
+ }
+
+ template <typename Archiver>
+ bool serialize(Archiver &AR) {
+ AR.prologue(TypeTraits<ELFSectionHeader>::size);
+
+ AR & sh_name;
+ AR & sh_type;
+ AR & sh_flags;
+ AR & sh_addr;
+ AR & sh_offset;
+ AR & sh_size;
+ AR & sh_link;
+ AR & sh_info;
+ AR & sh_addralign;
+ AR & sh_entsize;
+
+ AR.epilogue(TypeTraits<ELFSectionHeader>::size);
+ return AR;
+ }
+
+public:
+ word_t getFlags() const {
+ return sh_flags;
+ }
+
+ word_t getSize() const {
+ return sh_size;
+ }
+
+ word_t getAddressAlign() const {
+ return sh_addralign;
+ }
+
+ word_t getEntrySize() const {
+ return sh_entsize;
+ }
+};
+
+template <>
+class ELFSectionHeader<64> : public ELFSectionHeader_CRTP<64> {
+ friend class ELFSectionHeader_CRTP<64>;
+
+private:
+ xword_t sh_flags;
+ xword_t sh_size;
+ xword_t sh_addralign;
+ xword_t sh_entsize;
+
+private:
+ ELFSectionHeader() {
+ }
+
+ template <typename Archiver>
+ bool serialize(Archiver &AR) {
+ AR.prologue(TypeTraits<ELFSectionHeader>::size);
+
+ AR & sh_name;
+ AR & sh_type;
+ AR & sh_flags;
+ AR & sh_addr;
+ AR & sh_offset;
+ AR & sh_size;
+ AR & sh_link;
+ AR & sh_info;
+ AR & sh_addralign;
+ AR & sh_entsize;
+
+ AR.epilogue(TypeTraits<ELFSectionHeader>::size);
+ return AR;
+ }
+
+public:
+ xword_t getFlags() const {
+ return sh_flags;
+ }
+
+ xword_t getSize() const {
+ return sh_size;
+ }
+
+ xword_t getAddressAlign() const {
+ return sh_addralign;
+ }
+
+ xword_t getEntrySize() const {
+ return sh_entsize;
+ }
+};
+
+#endif // ELF_SECTION_HEADER_H
diff --git a/driver/linkloader/include/ELFSectionHeaderTable.h b/driver/linkloader/include/ELFSectionHeaderTable.h
new file mode 100644
index 0000000..fb7f9ed
--- /dev/null
+++ b/driver/linkloader/include/ELFSectionHeaderTable.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_HEADER_TABLE_H
+#define ELF_SECTION_HEADER_TABLE_H
+
+#include "ELFTypes.h"
+
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/ADT/StringMap.h>
+
+#include <vector>
+#include <string>
+
+template <unsigned Bitwidth>
+class ELFSectionHeaderTable {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+private:
+ std::vector<ELFSectionHeaderTy *> table;
+ llvm::StringMap<ELFSectionHeaderTy *> name_map;
+
+private:
+ ELFSectionHeaderTable() {
+ }
+
+public:
+ ~ELFSectionHeaderTable();
+
+ template <typename Archiver>
+ static ELFSectionHeaderTableTy *read(Archiver &AR, ELFObjectTy *owner);
+
+ ELFSectionHeaderTy const *operator[](size_t i) const {
+ return table[i];
+ }
+
+ ELFSectionHeaderTy *operator[](size_t i) {
+ return table[i];
+ }
+
+ void buildNameMap();
+
+ ELFSectionHeaderTy const *getByName(const std::string &name) const;
+ ELFSectionHeaderTy *getByName(const std::string &name);
+
+ void print() const;
+};
+
+#include "impl/ELFSectionHeaderTable.hxx"
+
+#endif // ELF_SECTION_HEADER_TABLE_H
diff --git a/driver/linkloader/include/ELFSectionNoBits.h b/driver/linkloader/include/ELFSectionNoBits.h
new file mode 100644
index 0000000..5c4b3f2
--- /dev/null
+++ b/driver/linkloader/include/ELFSectionNoBits.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_NOBITS_H
+#define ELF_SECTION_NOBITS_H
+
+#include "ELFTypes.h"
+#include "ELFSectionBits.h"
+#include "ELFSectionHeader.h"
+#include "MemChunk.h"
+
+template <unsigned Bitwidth>
+class ELFSectionNoBits : public ELFSectionBits<Bitwidth> {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+public:
+ template <typename Archiver>
+ static ELFSectionNoBits *read(Archiver &AR, ELFSectionHeaderTy const *sh);
+};
+
+#include "impl/ELFSectionNoBits.hxx"
+
+#endif // ELF_SECTION_NOBITS_H
diff --git a/driver/linkloader/include/ELFSectionProgBits.h b/driver/linkloader/include/ELFSectionProgBits.h
new file mode 100644
index 0000000..e0da71e
--- /dev/null
+++ b/driver/linkloader/include/ELFSectionProgBits.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_PROGBITS_H
+#define ELF_SECTION_PROGBITS_H
+
+#include "ELFTypes.h"
+#include "ELFSectionBits.h"
+#include "ELFSectionHeader.h"
+#include "MemChunk.h"
+#include "StubLayout.h"
+
+template <unsigned Bitwidth>
+class ELFSectionProgBits : public ELFSectionBits<Bitwidth> {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+private:
+ StubLayout *stubs;
+
+public:
+ template <typename Archiver>
+ static ELFSectionProgBits *read(Archiver &AR,
+ ELFObjectTy *owner,
+ ELFSectionHeaderTy const *sh);
+
+ StubLayout *getStubLayout() {
+ return stubs;
+ }
+
+ ELFSectionProgBits(int machine) {
+ switch(machine) {
+ case EM_ARM:
+ stubs = new StubLayoutARM();
+ break;
+
+ case EM_MIPS:
+ stubs = new StubLayoutMIPS();
+ break;
+
+ default:
+ stubs = NULL;
+ }
+ }
+
+ ~ELFSectionProgBits() {
+ if (stubs)
+ delete stubs;
+ }
+
+private:
+ template <typename Archiver>
+ bool serialize(Archiver &AR) {
+ ELFSectionHeaderTy const *sh = this->sh;
+ MemChunk &chunk = this->chunk;
+
+ AR.seek(sh->getOffset(), true);
+ AR.prologue(sh->getSize());
+ AR.readBytes(chunk.getBuffer(), sh->getSize());
+ AR.epilogue(sh->getSize());
+
+ return AR;
+ }
+};
+
+#include "impl/ELFSectionProgBits.hxx"
+
+#endif // ELF_SECTION_PROGBITS_H
diff --git a/driver/linkloader/include/ELFSectionRelTable.h b/driver/linkloader/include/ELFSectionRelTable.h
new file mode 100644
index 0000000..2799501
--- /dev/null
+++ b/driver/linkloader/include/ELFSectionRelTable.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_REL_TABLE_H
+#define ELF_SECTION_REL_TABLE_H
+
+#include "ELFTypes.h"
+#include "ELFSection.h"
+
+#include <string>
+#include <vector>
+
+template <unsigned Bitwidth>
+class ELFSectionRelTable : public ELFSection<Bitwidth> {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+private:
+ std::vector<ELFRelocTy *> table;
+
+private:
+ ELFSectionRelTable() { }
+
+public:
+ virtual ~ELFSectionRelTable();
+
+ virtual void print() const;
+
+ template <typename Archiver>
+ static ELFSectionRelTable *read(Archiver &AR, ELFSectionHeaderTy const *sh);
+
+ size_t size() const {
+ return table.size();
+ }
+
+ ELFRelocTy const *operator[](size_t index) const {
+ return table[index];
+ }
+
+ ELFRelocTy *operator[](size_t index) {
+ return table[index];
+ }
+
+ size_t getMaxNumStubs(ELFObjectTy const *) const;
+};
+
+#include "impl/ELFSectionRelTable.hxx"
+
+#endif // ELF_SECTION_REL_TABLE_H
diff --git a/driver/linkloader/include/ELFSectionStrTab.h b/driver/linkloader/include/ELFSectionStrTab.h
new file mode 100644
index 0000000..458dfa3
--- /dev/null
+++ b/driver/linkloader/include/ELFSectionStrTab.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_STRTAB_H
+#define ELF_SECTION_STRTAB_H
+
+#include "ELFTypes.h"
+#include "ELFSection.h"
+
+#include <vector>
+
+template <unsigned Bitwidth>
+class ELFSectionStrTab : public ELFSection<Bitwidth> {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+private:
+ ELFSectionHeaderTy const *section_header;
+ std::vector<char> buf;
+
+private:
+ ELFSectionStrTab() { }
+
+public:
+ template <typename Archiver>
+ static ELFSectionStrTab *read(Archiver &AR, ELFSectionHeaderTy const *sh);
+
+ virtual void print() const;
+
+ char const *operator[](size_t index) const {
+ return &*buf.begin() + index;
+ }
+};
+
+#include "impl/ELFSectionStrTab.hxx"
+
+#endif // ELF_SECTION_STRTAB_H
diff --git a/driver/linkloader/include/ELFSectionSymTab.h b/driver/linkloader/include/ELFSectionSymTab.h
new file mode 100644
index 0000000..821067f
--- /dev/null
+++ b/driver/linkloader/include/ELFSectionSymTab.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_SYMTAB_H
+#define ELF_SECTION_SYMTAB_H
+
+#include "ELFTypes.h"
+
+#include <llvm/ADT/StringMap.h>
+
+#include <vector>
+#include <string>
+
+template <unsigned Bitwidth>
+class ELFSectionSymTab : public ELFSection<Bitwidth> {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+private:
+ std::vector<ELFSymbolTy *> table;
+ llvm::StringMap<ELFSymbolTy *> name_map;
+
+private:
+ ELFSectionSymTab() { }
+
+public:
+ ~ELFSectionSymTab();
+
+ template <typename Archiver>
+ static ELFSectionSymTab *
+ read(Archiver &AR, ELFObjectTy *owner, ELFSectionHeaderTy const *sh);
+
+ virtual void print() const;
+
+ size_t size() const {
+ return table.size();
+ }
+
+ ELFSymbolTy const *operator[](size_t index) const {
+ return table[index];
+ }
+
+ ELFSymbolTy *operator[](size_t index) {
+ return table[index];
+ }
+
+ void buildNameMap();
+
+ ELFSymbolTy const *getByName(std::string const &name) const;
+
+ ELFSymbolTy *getByName(std::string const &name) {
+ return const_cast<ELFSymbolTy *>(
+ const_cast<ELFSectionSymTabTy const *>(this)->getByName(name));
+ }
+
+ size_t getFuncCount() const;
+
+ void getFuncNameList(size_t size, char const **list) const;
+
+ size_t getExternFuncCount() const;
+
+};
+
+#include "impl/ELFSectionSymTab.hxx"
+
+#endif // ELF_SECTION_SYMTAB_H
diff --git a/driver/linkloader/include/ELFSymbol.h b/driver/linkloader/include/ELFSymbol.h
new file mode 100644
index 0000000..d78ba5a
--- /dev/null
+++ b/driver/linkloader/include/ELFSymbol.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SYMBOL_H
+#define ELF_SYMBOL_H
+
+#include "ELFTypes.h"
+#include "ELF.h"
+
+#include <llvm/ADT/OwningPtr.h>
+
+#include <string>
+#include <algorithm>
+
+#include <stdint.h>
+#include <stdlib.h>
+
+class ELFSymbolHelperMixin {
+protected:
+ static char const *getTypeStr(uint8_t);
+ static char const *getBindingAttributeStr(uint8_t);
+ static char const *getVisibilityStr(uint8_t);
+};
+
+template <unsigned Bitwidth>
+class ELFSymbol_CRTP : private ELFSymbolHelperMixin {
+public:
+ ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
+
+protected:
+ ELFObject<Bitwidth> const *owner;
+
+ size_t index;
+
+ word_t st_name;
+ byte_t st_info;
+ byte_t st_other;
+ half_t st_shndx;
+ addr_t st_value;
+ symsize_t st_size;
+
+ mutable void *my_addr;
+
+protected:
+ ELFSymbol_CRTP() { my_addr = 0; }
+
+ ~ELFSymbol_CRTP() {
+#if 0
+ if (my_addr != 0 &&
+ getType() == STT_OBJECT &&
+ getSectionIndex() == SHN_COMMON) {
+ std::free(my_addr);
+ }
+#endif
+ }
+
+public:
+ size_t getIndex() const {
+ return index;
+ }
+
+ word_t getNameIndex() const {
+ return st_name;
+ }
+
+ char const *getName() const;
+
+// I don't want to include elf.h in .h file, so define those macro by ourself.
+#define ELF_ST_BIND(i) ((i)>>4)
+#define ELF_ST_TYPE(i) ((i)&0xf)
+#define ELF_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
+ byte_t getType() const {
+ return ELF_ST_TYPE(st_info);
+ }
+
+ byte_t getBindingAttribute() const {
+ return ELF_ST_BIND(st_info);
+ }
+#undef ELF_ST_BIND
+#undef ELF_ST_TYPE
+#undef ELF_ST_INFO
+
+#define ELF_ST_VISIBILITY(o) ((o)&0x3)
+ byte_t getVisibility() const {
+ return ELF_ST_VISIBILITY(st_other);
+ }
+#undef ELF_ST_VISIBILITY
+
+ half_t getSectionIndex() const {
+ return st_shndx;
+ }
+
+ addr_t getValue() const {
+ return st_value;
+ }
+
+ symsize_t getSize() const {
+ return st_size;
+ }
+
+ void *getAddress(int machine, bool autoAlloc = true) const;
+
+ void setAddress(void *addr) {
+ my_addr = addr;
+ }
+
+ bool isValid() const {
+ // FIXME: Should check the correctness of the section header.
+ return true;
+ }
+
+ bool isConcreteFunc() const {
+ return getType() == STT_FUNC;
+ }
+
+ bool isExternFunc() const {
+ return getType() == STT_NOTYPE;
+ }
+
+ template <typename Archiver>
+ static ELFSymbolTy *
+ read(Archiver &AR, ELFObject<Bitwidth> const *owner, size_t index = 0);
+
+ void print(bool shouldPrintHeader = false) const;
+
+private:
+ ELFSymbolTy *concrete() {
+ return static_cast<ELFSymbolTy *>(this);
+ }
+
+ ELFSymbolTy const *concrete() const {
+ return static_cast<ELFSymbolTy const *>(this);
+ }
+};
+
+template <>
+class ELFSymbol<32> : public ELFSymbol_CRTP<32> {
+ friend class ELFSymbol_CRTP<32>;
+
+private:
+ ELFSymbol() {
+ }
+
+ template <typename Archiver>
+ bool serialize(Archiver &AR) {
+ AR.prologue(TypeTraits<ELFSymbol>::size);
+
+ AR & st_name;
+ AR & st_value;
+ AR & st_size;
+ AR & st_info;
+ AR & st_other;
+ AR & st_shndx;
+
+ AR.epilogue(TypeTraits<ELFSymbol>::size);
+ return AR;
+ }
+};
+
+template <>
+class ELFSymbol<64> : public ELFSymbol_CRTP<64> {
+ friend class ELFSymbol_CRTP<64>;
+
+private:
+ ELFSymbol() {
+ }
+
+ template <typename Archiver>
+ bool serialize(Archiver &AR) {
+ AR.prologue(TypeTraits<ELFSymbol>::size);
+
+ AR & st_name;
+ AR & st_info;
+ AR & st_other;
+ AR & st_shndx;
+ AR & st_value;
+ AR & st_size;
+
+ AR.epilogue(TypeTraits<ELFSymbol>::size);
+ return AR;
+ }
+};
+
+#include "impl/ELFSymbol.hxx"
+
+#endif // ELF_SYMBOL_H
diff --git a/driver/linkloader/include/ELFTypes.h b/driver/linkloader/include/ELFTypes.h
new file mode 100644
index 0000000..3e99f78
--- /dev/null
+++ b/driver/linkloader/include/ELFTypes.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_TYPES_H
+#define ELF_TYPES_H
+
+#include "utils/traits.h"
+
+#include <stdint.h>
+#include <llvm/Support/raw_ostream.h>
+
+
+// ELF structure forward declarations
+template <unsigned Bitwidth> class ELFHeader;
+template <unsigned Bitwidth> class ELFObject;
+template <unsigned Bitwidth> class ELFProgramHeader;
+template <unsigned Bitwidth> class ELFReloc;
+template <unsigned Bitwidth> class ELFRelocRel; // For TypeTraits
+template <unsigned Bitwidth> class ELFRelocRela; // For TypeTraits
+template <unsigned Bitwidth> class ELFSection;
+template <unsigned Bitwidth> class ELFSectionBits;
+template <unsigned Bitwidth> class ELFSectionHeader;
+template <unsigned Bitwidth> class ELFSectionHeaderTable;
+template <unsigned Bitwidth> class ELFSectionNoBits;
+template <unsigned Bitwidth> class ELFSectionProgBits;
+template <unsigned Bitwidth> class ELFSectionRelTable;
+template <unsigned Bitwidth> class ELFSectionStrTab;
+template <unsigned Bitwidth> class ELFSectionSymTab;
+template <unsigned Bitwidth> class ELFSymbol;
+
+// Note: Following TypeTraits specialization MUST be compliant to the
+// System V Application Binary Interface, Chap 4, Data Representation.
+
+TYPE_TRAITS_SPECIALIZE(ELFHeader<32> , 52, 4)
+TYPE_TRAITS_SPECIALIZE(ELFHeader<64> , 64, 8)
+
+TYPE_TRAITS_SPECIALIZE(ELFProgramHeader<32> , 32, 4)
+TYPE_TRAITS_SPECIALIZE(ELFProgramHeader<64> , 56, 8)
+
+TYPE_TRAITS_SPECIALIZE(ELFSectionHeader<32> , 40, 4)
+TYPE_TRAITS_SPECIALIZE(ELFSectionHeader<64> , 64, 8)
+
+TYPE_TRAITS_SPECIALIZE(ELFSymbol<32> , 16, 4)
+TYPE_TRAITS_SPECIALIZE(ELFSymbol<64> , 24, 8)
+
+TYPE_TRAITS_SPECIALIZE(ELFRelocRel<32> , 8, 4)
+TYPE_TRAITS_SPECIALIZE(ELFRelocRel<64> , 16, 8)
+
+TYPE_TRAITS_SPECIALIZE(ELFRelocRela<32> , 12, 4)
+TYPE_TRAITS_SPECIALIZE(ELFRelocRela<64> , 24, 8)
+
+
+// ELF primitive type wrappers
+namespace detail {
+#define ELF_TYPE_WRAPPER(TYPE, IMPL) \
+ struct TYPE { \
+ IMPL value; \
+ \
+ TYPE() : value(0) { } \
+ TYPE(IMPL val) : value(val) { } \
+ \
+ TYPE &operator=(TYPE const &with) { value = with.value; return *this; } \
+ TYPE &operator=(IMPL val) { value = val; return *this; } \
+ \
+ operator IMPL() const { return value; } \
+ };
+
+ ELF_TYPE_WRAPPER(ELFHalf , uint16_t)
+ ELF_TYPE_WRAPPER(ELFWord , uint32_t)
+ ELF_TYPE_WRAPPER(ELFSword , int32_t)
+ ELF_TYPE_WRAPPER(ELFXword , uint64_t)
+ ELF_TYPE_WRAPPER(ELFSxword , int64_t)
+ ELF_TYPE_WRAPPER(ELF32Address , uint32_t)
+ ELF_TYPE_WRAPPER(ELF32Offset , uint32_t)
+ ELF_TYPE_WRAPPER(ELF64Address , uint64_t)
+ ELF_TYPE_WRAPPER(ELF64Offset , uint64_t)
+
+#undef ELF_TYPE_WRAPPER
+
+ extern llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ ELF32Address const &);
+ extern llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ ELF32Offset const &);
+ extern llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ ELF64Address const &);
+ extern llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ ELF64Offset const &);
+}
+
+// Note: Following TypeTraits specialization MUST be compliant to the
+// System V Application Binary Interface, Chap 4, Data Representation.
+
+TYPE_TRAITS_SPECIALIZE(detail::ELFHalf , 2, 2)
+TYPE_TRAITS_SPECIALIZE(detail::ELFWord , 4, 4)
+TYPE_TRAITS_SPECIALIZE(detail::ELFSword , 4, 4)
+TYPE_TRAITS_SPECIALIZE(detail::ELFXword , 8, 8)
+TYPE_TRAITS_SPECIALIZE(detail::ELFSxword , 8, 8)
+TYPE_TRAITS_SPECIALIZE(detail::ELF32Address , 4, 4)
+TYPE_TRAITS_SPECIALIZE(detail::ELF32Offset , 4, 4)
+TYPE_TRAITS_SPECIALIZE(detail::ELF64Address , 8, 8)
+TYPE_TRAITS_SPECIALIZE(detail::ELF64Offset , 8, 8)
+
+template <unsigned Bitwidth>
+struct ELFPrimitiveTypes;
+
+template <>
+struct ELFPrimitiveTypes<32> {
+ typedef detail::ELF32Address address;
+ typedef detail::ELF32Offset offset;
+
+ typedef unsigned char byte;
+ typedef detail::ELFHalf half;
+ typedef detail::ELFWord word;
+ typedef detail::ELFSword sword;
+
+ typedef detail::ELFWord relinfo;
+ typedef detail::ELFSword addend;
+ typedef detail::ELFWord symsize;
+
+ // Note: Don't use these types. They are not in the specification of
+ // ELF 32. However, we need these typedefs to define the type introduce
+ // macro.
+ typedef void xword;
+ typedef void sxword;
+};
+
+template <>
+struct ELFPrimitiveTypes<64> {
+ typedef detail::ELF64Address address;
+ typedef detail::ELF64Offset offset;
+
+ typedef unsigned char byte;
+ typedef detail::ELFHalf half;
+ typedef detail::ELFWord word;
+ typedef detail::ELFSword sword;
+ typedef detail::ELFXword xword;
+ typedef detail::ELFSxword sxword;
+
+ typedef detail::ELFXword relinfo;
+ typedef detail::ELFSxword addend;
+ typedef detail::ELFXword symsize;
+};
+
+
+// Macros to introduce these ELF types to a specific scope
+
+#define ELF_STRUCT_TYPE_INTRO_TO_SCOPE(BITWIDTH) \
+ typedef ELFHeader<BITWIDTH> ELFHeaderTy; \
+ typedef ELFObject<BITWIDTH> ELFObjectTy; \
+ typedef ELFProgramHeader<BITWIDTH> ELFProgramHeaderTy; \
+ typedef ELFReloc<BITWIDTH> ELFRelocTy; \
+ typedef ELFRelocRel<BITWIDTH> ELFRelocRelTy; \
+ typedef ELFRelocRela<BITWIDTH> ELFRelocRelaTy; \
+ typedef ELFSection<BITWIDTH> ELFSectionTy; \
+ typedef ELFSectionBits<BITWIDTH> ELFSectionBitsTy; \
+ typedef ELFSectionHeader<BITWIDTH> ELFSectionHeaderTy; \
+ typedef ELFSectionHeaderTable<BITWIDTH> ELFSectionHeaderTableTy; \
+ typedef ELFSectionNoBits<BITWIDTH> ELFSectionNoBitsTy; \
+ typedef ELFSectionProgBits<BITWIDTH> ELFSectionProgBitsTy; \
+ typedef ELFSectionRelTable<BITWIDTH> ELFSectionRelTableTy; \
+ typedef ELFSectionStrTab<BITWIDTH> ELFSectionStrTabTy; \
+ typedef ELFSectionSymTab<BITWIDTH> ELFSectionSymTabTy; \
+ typedef ELFSymbol<BITWIDTH> ELFSymbolTy;
+
+
+#define ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(BITWIDTH) \
+ /* ELF structures */ \
+ ELF_STRUCT_TYPE_INTRO_TO_SCOPE(BITWIDTH) \
+ \
+ /* ELF primitives */ \
+ typedef typename ELFPrimitiveTypes<BITWIDTH>::address addr_t; \
+ typedef typename ELFPrimitiveTypes<BITWIDTH>::offset offset_t; \
+ typedef typename ELFPrimitiveTypes<BITWIDTH>::byte byte_t; \
+ typedef typename ELFPrimitiveTypes<BITWIDTH>::half half_t; \
+ typedef typename ELFPrimitiveTypes<BITWIDTH>::word word_t; \
+ typedef typename ELFPrimitiveTypes<BITWIDTH>::sword sword_t; \
+ typedef typename ELFPrimitiveTypes<BITWIDTH>::xword xword_t; \
+ typedef typename ELFPrimitiveTypes<BITWIDTH>::sxword sxword_t; \
+ typedef typename ELFPrimitiveTypes<BITWIDTH>::relinfo relinfo_t; \
+ typedef typename ELFPrimitiveTypes<BITWIDTH>::addend addend_t; \
+ typedef typename ELFPrimitiveTypes<BITWIDTH>::symsize symsize_t;
+
+
+#define ELF_TYPE_INTRO_TO_SCOPE(BITWIDTH) \
+ /* ELF structures */ \
+ ELF_STRUCT_TYPE_INTRO_TO_SCOPE(BITWIDTH) \
+ \
+ /* ELF primitives */ \
+ typedef ELFPrimitiveTypes<BITWIDTH>::address addr_t; \
+ typedef ELFPrimitiveTypes<BITWIDTH>::offset offset_t; \
+ typedef ELFPrimitiveTypes<BITWIDTH>::byte byte_t; \
+ typedef ELFPrimitiveTypes<BITWIDTH>::half half_t; \
+ typedef ELFPrimitiveTypes<BITWIDTH>::word word_t; \
+ typedef ELFPrimitiveTypes<BITWIDTH>::sword sword_t; \
+ typedef ELFPrimitiveTypes<BITWIDTH>::xword xword_t; \
+ typedef ELFPrimitiveTypes<BITWIDTH>::sxword sxword_t; \
+ typedef ELFPrimitiveTypes<BITWIDTH>::relinfo relinfo_t; \
+ typedef ELFPrimitiveTypes<BITWIDTH>::addend addend_t; \
+ typedef ELFPrimitiveTypes<BITWIDTH>::symsize symsize_t;
+
+
+#endif // ELF_TYPES_H
diff --git a/driver/linkloader/include/GOT.h b/driver/linkloader/include/GOT.h
new file mode 100644
index 0000000..b72bf66
--- /dev/null
+++ b/driver/linkloader/include/GOT.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GOT_H
+#define GOT_H
+
+#include "utils/rsl_assert.h"
+#include "ELF.h"
+
+#define GP_OFFSET ((int)0x8000)
+#define GOT_SIZE (1 << 16) // bytes
+#define GOT_ENTRY_SIZE 4 // bytes
+#define NUM_OF_GOT_ENTRY (GOT_SIZE/GOT_ENTRY_SIZE)
+
+void *got_address();
+int search_got(int symbol_index, void *addr, uint8_t bind_type);
+
+#endif // GOT_H
diff --git a/driver/linkloader/include/MemChunk.h b/driver/linkloader/include/MemChunk.h
new file mode 100644
index 0000000..fb853e9
--- /dev/null
+++ b/driver/linkloader/include/MemChunk.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEM_CHUNK_H
+#define MEM_CHUNK_H
+
+#include <stddef.h>
+#include <stdlib.h>
+
+class MemChunk {
+private:
+ unsigned char *buf;
+ size_t buf_size;
+
+public:
+ MemChunk();
+
+ ~MemChunk();
+
+ bool allocate(size_t size);
+
+ void print() const;
+
+ bool protect(int prot);
+
+ unsigned char const *getBuffer() const {
+ return buf;
+ }
+
+ unsigned char *getBuffer() {
+ return buf;
+ }
+
+ unsigned char &operator[](size_t index) {
+ return buf[index];
+ }
+
+ unsigned char const &operator[](size_t index) const {
+ return buf[index];
+ }
+
+ size_t size() const {
+ return buf_size;
+ }
+
+};
+
+#endif // MEM_CHUNK_H
diff --git a/driver/linkloader/include/StubLayout.h b/driver/linkloader/include/StubLayout.h
new file mode 100644
index 0000000..9705743
--- /dev/null
+++ b/driver/linkloader/include/StubLayout.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STUB_LAYOUT_H
+#define STUB_LAYOUT_H
+
+#include <map>
+#include <stdlib.h>
+
+class StubLayout {
+private:
+ unsigned char *table;
+ size_t count;
+
+ std::map<void *, void *> stub_index;
+
+public:
+ StubLayout();
+ virtual ~StubLayout() { }
+
+ void initStubTable(unsigned char *table, size_t count);
+ void *allocateStub(void *addr = 0);
+
+ size_t calcStubTableSize(size_t count) const;
+ virtual size_t getUnitStubSize() const = 0;
+
+private:
+ virtual void setStubAddress(void *stub, void *addr) = 0;
+
+};
+
+class StubLayoutARM : public StubLayout {
+public:
+ StubLayoutARM() { }
+ size_t getUnitStubSize() const;
+
+private:
+ virtual void setStubAddress(void *stub, void *addr);
+};
+
+class StubLayoutMIPS : public StubLayout {
+public:
+ StubLayoutMIPS() { }
+ size_t getUnitStubSize() const;
+
+private:
+ virtual void setStubAddress(void *stub, void *addr);
+};
+
+
+#endif // STUB_LAYOUT_H
diff --git a/driver/linkloader/include/impl/ELFHeader.hxx b/driver/linkloader/include/impl/ELFHeader.hxx
new file mode 100644
index 0000000..993b0e2
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFHeader.hxx
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_HEADER_HXX
+#define ELF_HEADER_HXX
+
+#include "utils/raw_ostream.h"
+
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/Format.h>
+
+template <unsigned Bitwidth>
+void ELFHeader<Bitwidth>::print() {
+ using namespace llvm;
+
+ out() << fillformat('=', 79) << '\n';
+ out().changeColor(raw_ostream::WHITE, true);
+ out() << "ELF Header\n";
+ out().resetColor();
+ out() << fillformat('-', 79) << '\n';
+
+#define PRINT_LINT(title, value) \
+ out() << format(" %-32s : ", (char const *)(title)) << (value) << '\n'
+ PRINT_LINT("Class", getClassStr(getClass()));
+ PRINT_LINT("Endianness", getEndiannessStr(getEndianness()));
+ PRINT_LINT("Header Version", (unsigned)getVersion());
+ PRINT_LINT("OS ABI", getOSABIStr(getOSABI()));
+ PRINT_LINT("ABI Version", (unsigned)getABIVersion());
+ PRINT_LINT("Object Type", getObjectTypeStr(getObjectType()));
+ PRINT_LINT("Machine", getMachineStr(getMachine()));
+ PRINT_LINT("Version", getVersionStr(getVersion()));
+ PRINT_LINT("Entry Address", getEntryAddress());
+ PRINT_LINT("Program Header Offset", getProgramHeaderTableOffset());
+ PRINT_LINT("Section Header Offset", getSectionHeaderTableOffset());
+ PRINT_LINT("Flags", getFlags());
+ PRINT_LINT("ELF Header Size", getELFHeaderSize());
+ PRINT_LINT("Program Header Size", getProgramHeaderEntrySize());
+ PRINT_LINT("Program Header Num", getProgramHeaderNum());
+ PRINT_LINT("Section Header Size", getSectionHeaderEntrySize());
+ PRINT_LINT("Section Header Num", getSectionHeaderNum());
+ PRINT_LINT("String Section Index", getStringSectionIndex());
+#undef PRINT_LINT
+
+ out() << fillformat('=', 79) << "\n\n";
+}
+
+#endif // ELF_HEADER_HXX
diff --git a/driver/linkloader/include/impl/ELFObject.hxx b/driver/linkloader/include/impl/ELFObject.hxx
new file mode 100644
index 0000000..ca47820
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFObject.hxx
@@ -0,0 +1,740 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_OBJECT_HXX
+#define ELF_OBJECT_HXX
+
+#include "ELFHeader.h"
+#include "ELFReloc.h"
+#include "ELFSection.h"
+#include "ELFSectionHeaderTable.h"
+#include "StubLayout.h"
+#include "GOT.h"
+#include "ELF.h"
+
+#include <llvm/ADT/SmallVector.h>
+
+#include "utils/rsl_assert.h"
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+inline ELFObject<Bitwidth> *
+ELFObject<Bitwidth>::read(Archiver &AR) {
+ llvm::OwningPtr<ELFObjectTy> object(new ELFObjectTy());
+
+ // Read header
+ object->header.reset(ELFHeaderTy::read(AR));
+ if (!object->header) {
+ return 0;
+ }
+
+ // Read section table
+ object->shtab.reset(ELFSectionHeaderTableTy::read(AR, object.get()));
+ if (!object->shtab) {
+ return 0;
+ }
+
+ // Read each section
+ llvm::SmallVector<size_t, 4> progbits_ndx;
+ for (size_t i = 0; i < object->header->getSectionHeaderNum(); ++i) {
+ if ((*object->shtab)[i]->getType() == SHT_PROGBITS) {
+ object->stab.push_back(NULL);
+ progbits_ndx.push_back(i);
+ } else {
+ llvm::OwningPtr<ELFSectionTy> sec(
+ ELFSectionTy::read(AR, object.get(), (*object->shtab)[i]));
+ object->stab.push_back(sec.take());
+ }
+ }
+
+ object->shtab->buildNameMap();
+ ELFSectionSymTabTy *symtab =
+ static_cast<ELFSectionSymTabTy *>(object->getSectionByName(".symtab"));
+ rsl_assert(symtab && "Symtab is required.");
+ symtab->buildNameMap();
+
+ for (size_t i = 0; i < progbits_ndx.size(); ++i) {
+ size_t index = progbits_ndx[i];
+
+ llvm::OwningPtr<ELFSectionTy> sec(
+ ELFSectionTy::read(AR, object.get(), (*object->shtab)[index]));
+ object->stab[index] = sec.take();
+ }
+
+ return object.take();
+}
+
+template <unsigned Bitwidth>
+inline char const *ELFObject<Bitwidth>::getSectionName(size_t i) const {
+ ELFSectionTy const *sec = stab[header->getStringSectionIndex()];
+
+ if (sec) {
+ ELFSectionStrTabTy const &st =
+ static_cast<ELFSectionStrTabTy const &>(*sec);
+ return st[i];
+ }
+
+ return NULL;
+}
+
+template <unsigned Bitwidth>
+inline ELFSection<Bitwidth> const *
+ELFObject<Bitwidth>::getSectionByIndex(size_t i) const {
+ return stab[i];
+}
+
+template <unsigned Bitwidth>
+inline ELFSection<Bitwidth> *
+ELFObject<Bitwidth>::getSectionByIndex(size_t i) {
+ return stab[i];
+}
+
+template <unsigned Bitwidth>
+inline ELFSection<Bitwidth> const *
+ELFObject<Bitwidth>::getSectionByName(std::string const &str) const {
+ size_t idx = getSectionHeaderTable()->getByName(str)->getIndex();
+ return stab[idx];
+}
+
+template <unsigned Bitwidth>
+inline ELFSection<Bitwidth> *
+ELFObject<Bitwidth>::getSectionByName(std::string const &str) {
+ ELFObjectTy const *const_this = this;
+ ELFSectionTy const *sptr = const_this->getSectionByName(str);
+ // Const cast for the same API's const and non-const versions.
+ return const_cast<ELFSectionTy *>(sptr);
+}
+
+
+template <unsigned Bitwidth>
+inline void ELFObject<Bitwidth>::
+relocateARM(void *(*find_sym)(void *context, char const *name),
+ void *context,
+ ELFSectionRelTableTy *reltab,
+ ELFSectionProgBitsTy *text) {
+ // FIXME: Should be implement in independent files.
+ rsl_assert(Bitwidth == 32 && "ARM only have 32 bits.");
+
+ ELFSectionSymTabTy *symtab =
+ static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
+ rsl_assert(symtab && "Symtab is required.");
+
+ for (size_t i = 0; i < reltab->size(); ++i) {
+ // FIXME: Can not implement here, use Fixup!
+ ELFRelocTy *rel = (*reltab)[i];
+ ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
+
+ // FIXME: May be not uint32_t *.
+ typedef int32_t Inst_t;
+ Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
+ Inst_t P = (Inst_t)(int64_t)inst;
+ Inst_t A = 0;
+ Inst_t S = (Inst_t)(int64_t)sym->getAddress(EM_ARM);
+ Inst_t T = 0;
+
+ if (sym->isConcreteFunc() && (sym->getValue() & 0x1)) {
+ T = 1;
+ }
+
+ word_t reltype = rel->getType();
+ switch (reltype) {
+ default:
+ rsl_assert(0 && "Not implemented relocation type.");
+ break;
+
+ case R_ARM_ABS32:
+ {
+ if (S == 0 && sym->getType() == STT_NOTYPE) {
+ void *ext_sym = find_sym(context, sym->getName());
+ if (!ext_sym) {
+ missingSymbols = true;
+ }
+ S = (Inst_t)(uintptr_t)ext_sym;
+ sym->setAddress(ext_sym);
+ }
+ A = *inst;
+ *inst = (S + A) | T;
+ }
+ break;
+
+ // FIXME: Predefine relocation codes.
+ case R_ARM_CALL:
+ case R_ARM_THM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_THM_JUMP24:
+ {
+#define SIGN_EXTEND(x, l) (((x)^(1<<((l)-1)))-(1<<(l-1)))
+ if (reltype == R_ARM_CALL || reltype == R_ARM_JUMP24) {
+ A = (Inst_t)(int64_t)SIGN_EXTEND(*inst & 0xFFFFFF, 24);
+ A <<= 2;
+ } else {
+ // Hack for two 16bit.
+ *inst = ((*inst >> 16) & 0xFFFF) | (*inst << 16);
+ Inst_t s = (*inst >> 26) & 0x1u, // 26
+ u = (*inst >> 16) & 0x3FFu, // 25-16
+ l = *inst & 0x7FFu, // 10-0
+ j1 = (*inst >> 13) & 0x1u, // 13
+ j2 = (*inst >> 11) & 0x1u; // 11
+ Inst_t i1 = (~(j1 ^ s)) & 0x1u,
+ i2 = (~(j2 ^ s)) & 0x1u;
+ // [31-25][24][23][22][21-12][11-1][0]
+ // 0 s i1 i2 u l 0
+ A = SIGN_EXTEND((s << 23) | (i1 << 22) | (i2 << 21) | (u << 11) | l, 24);
+ A <<= 1;
+ }
+#undef SIGN_EXTEND
+
+ void *callee_addr = sym->getAddress(EM_ARM);
+
+ switch (sym->getType()) {
+ default:
+ rsl_assert(0 && "Wrong type for R_ARM_CALL relocation.");
+ abort();
+ break;
+
+ case STT_FUNC:
+ // NOTE: Callee function is in the object file, but it may be
+ // in different PROGBITS section (which may be far call).
+
+ if (callee_addr == 0) {
+ rsl_assert(0 && "We should get function address at previous "
+ "sym->getAddress(EM_ARM) function call.");
+ abort();
+ }
+ break;
+
+ case STT_NOTYPE:
+ // NOTE: Callee function is an external function. Call find_sym
+ // if it has not resolved yet.
+
+ if (callee_addr == 0) {
+ callee_addr = find_sym(context, sym->getName());
+ if (!callee_addr) {
+ missingSymbols = true;
+ }
+ sym->setAddress(callee_addr);
+ }
+ break;
+ }
+
+ // Get the stub for this function
+ StubLayout *stub_layout = text->getStubLayout();
+
+ if (!stub_layout) {
+ llvm::errs() << "unable to get stub layout." << "\n";
+ abort();
+ }
+
+ void *stub = stub_layout->allocateStub(callee_addr);
+
+ if (!stub) {
+ llvm::errs() << "unable to allocate stub." << "\n";
+ abort();
+ }
+
+ //LOGI("Function %s: using stub %p\n", sym->getName(), stub);
+ S = (uint32_t)(uintptr_t)stub;
+
+ if (reltype == R_ARM_CALL || reltype == R_ARM_JUMP24) {
+ // Relocate the R_ARM_CALL relocation type
+ uint32_t result = (S + A - P) >> 2;
+
+ if (result > 0x007FFFFF && result < 0xFF800000) {
+ rsl_assert(0 && "Stub is still too far");
+ abort();
+ }
+
+ *inst = ((result) & 0x00FFFFFF) | (*inst & 0xFF000000);
+ } else {
+ P &= ~0x3; // Base address align to 4 bytes. (For BLX.)
+
+ // Relocate the R_ARM_THM_CALL relocation type
+ uint32_t result = (S + A - P) >> 1;
+
+ if (result > 0x007FFFFF && result < 0xFF800000) {
+ rsl_assert(0 && "Stub is still too far");
+ abort();
+ }
+
+ //*inst &= 0xF800D000u;
+ // Rewrite instruction to BLX. (Stub is always ARM.)
+ *inst &= 0xF800C000u;
+ // [31-25][24][23][22][21-12][11-1][0]
+ // 0 s i1 i2 u l 0
+ Inst_t s = (result >> 23) & 0x1u, // 26
+ u = (result >> 11) & 0x3FFu, // 25-16
+ // For BLX, bit [0] is 0.
+ l = result & 0x7FEu, // 10-0
+ i1 = (result >> 22) & 0x1u,
+ i2 = (result >> 21) & 0x1u;
+ Inst_t j1 = ((~i1) ^ s) & 0x01u, // 13
+ j2 = ((~i2) ^ s) & 0x01u; // 11
+ *inst |= s << 26;
+ *inst |= u << 16;
+ *inst |= l;
+ *inst |= j1 << 13;
+ *inst |= j2 << 11;
+ // Hack for two 16bit.
+ *inst = ((*inst >> 16) & 0xFFFF) | (*inst << 16);
+ }
+ }
+ break;
+ case R_ARM_MOVT_ABS:
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ {
+ if (S == 0 && sym->getType() == STT_NOTYPE) {
+ void *ext_sym = find_sym(context, sym->getName());
+ if (!ext_sym) {
+ missingSymbols = true;
+ }
+ S = (Inst_t)(uintptr_t)ext_sym;
+ sym->setAddress(ext_sym);
+ }
+ if (reltype == R_ARM_MOVT_ABS
+ || reltype == R_ARM_THM_MOVT_ABS) {
+ S >>= 16;
+ }
+
+ if (reltype == R_ARM_MOVT_ABS
+ || reltype == R_ARM_MOVW_ABS_NC) {
+ // No need sign extend.
+ A = ((*inst & 0xF0000) >> 4) | (*inst & 0xFFF);
+ uint32_t result = (S + A);
+ *inst = (((result) & 0xF000) << 4) |
+ ((result) & 0xFFF) |
+ (*inst & 0xFFF0F000);
+ } else {
+ // Hack for two 16bit.
+ *inst = ((*inst >> 16) & 0xFFFF) | (*inst << 16);
+ // imm16: [19-16][26][14-12][7-0]
+ A = (((*inst >> 4) & 0xF000u) |
+ ((*inst >> 15) & 0x0800u) |
+ ((*inst >> 4) & 0x0700u) |
+ ( *inst & 0x00FFu));
+ uint32_t result;
+ if (reltype == R_ARM_THM_MOVT_ABS) {
+ result = (S + A);
+ } else {
+ result = (S + A) | T;
+ }
+ // imm16: [19-16][26][14-12][7-0]
+ *inst &= 0xFBF08F00u;
+ *inst |= (result & 0xF000u) << 4;
+ *inst |= (result & 0x0800u) << 15;
+ *inst |= (result & 0x0700u) << 4;
+ *inst |= (result & 0x00FFu);
+ // Hack for two 16bit.
+ *inst = ((*inst >> 16) & 0xFFFF) | (*inst << 16);
+ }
+ }
+ break;
+ }
+ //llvm::errs() << "S: " << (void *)S << '\n';
+ //llvm::errs() << "A: " << (void *)A << '\n';
+ //llvm::errs() << "P: " << (void *)P << '\n';
+ //llvm::errs() << "S+A: " << (void *)(S+A) << '\n';
+ //llvm::errs() << "S+A-P: " << (void *)(S+A-P) << '\n';
+ }
+}
+
+template <unsigned Bitwidth>
+inline void ELFObject<Bitwidth>::
+relocateX86_64(void *(*find_sym)(void *context, char const *name),
+ void *context,
+ ELFSectionRelTableTy *reltab,
+ ELFSectionProgBitsTy *text) {
+ rsl_assert(Bitwidth == 64 && "Only support X86_64.");
+
+ ELFSectionSymTabTy *symtab =
+ static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
+ rsl_assert(symtab && "Symtab is required.");
+
+ for (size_t i = 0; i < reltab->size(); ++i) {
+ // FIXME: Can not implement here, use Fixup!
+ ELFRelocTy *rel = (*reltab)[i];
+ ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
+
+ //typedef uint64_t Inst_t;
+ typedef int32_t Inst_t;
+ Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
+ Inst_t P = (Inst_t)(int64_t)inst;
+ Inst_t A = (Inst_t)(int64_t)rel->getAddend();
+ Inst_t S = (Inst_t)(int64_t)sym->getAddress(EM_X86_64);
+
+ if (S == 0) {
+ S = (Inst_t)(int64_t)find_sym(context, sym->getName());
+ if (!S) {
+ missingSymbols = true;
+ }
+ sym->setAddress((void *)S);
+ }
+
+ switch (rel->getType()) {
+ default:
+ rsl_assert(0 && "Not implemented relocation type.");
+ break;
+
+ // FIXME: XXX: R_X86_64_64 is 64 bit, there is a big problem here.
+ case 1: // R_X86_64_64
+ *inst = (S+A);
+ break;
+
+ case 2: // R_X86_64_PC32
+ *inst = (S+A-P);
+ break;
+
+ case 10: // R_X86_64_32
+ case 11: // R_X86_64_32S
+ *inst = (S+A);
+ break;
+ }
+ }
+}
+
+template <unsigned Bitwidth>
+inline void ELFObject<Bitwidth>::
+relocateX86_32(void *(*find_sym)(void *context, char const *name),
+ void *context,
+ ELFSectionRelTableTy *reltab,
+ ELFSectionProgBitsTy *text) {
+ rsl_assert(Bitwidth == 32 && "Only support X86.");
+
+ ELFSectionSymTabTy *symtab =
+ static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
+ rsl_assert(symtab && "Symtab is required.");
+
+ for (size_t i = 0; i < reltab->size(); ++i) {
+ // FIXME: Can not implement here, use Fixup!
+ ELFRelocTy *rel = (*reltab)[i];
+ ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
+
+ //typedef uint64_t Inst_t;
+ typedef int32_t Inst_t;
+ Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
+ Inst_t P = (Inst_t)(uintptr_t)inst;
+ Inst_t A = (Inst_t)(uintptr_t)*inst;
+ Inst_t S = (Inst_t)(uintptr_t)sym->getAddress(EM_386);
+
+ if (S == 0) {
+ S = (Inst_t)(uintptr_t)find_sym(context, sym->getName());
+ if (!S) {
+ missingSymbols = true;
+ }
+ sym->setAddress((void *)S);
+ }
+
+ switch (rel->getType()) {
+ default:
+ rsl_assert(0 && "Not implemented relocation type.");
+ break;
+
+ case R_386_PC32:
+ *inst = (S+A-P);
+ break;
+
+ case R_386_32:
+ *inst = (S+A);
+ break;
+ }
+ }
+}
+
+template <unsigned Bitwidth>
+inline void ELFObject<Bitwidth>::
+relocateMIPS(void *(*find_sym)(void *context, char const *name),
+ void *context,
+ ELFSectionRelTableTy *reltab,
+ ELFSectionProgBitsTy *text) {
+ rsl_assert(Bitwidth == 32 && "Only support 32-bit MIPS.");
+
+ ELFSectionSymTabTy *symtab =
+ static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
+ rsl_assert(symtab && "Symtab is required.");
+
+ for (size_t i = 0; i < reltab->size(); ++i) {
+ // FIXME: Can not implement here, use Fixup!
+ ELFRelocTy *rel = (*reltab)[i];
+ ELFSymbolTy *sym = (*symtab)[rel->getSymTabIndex()];
+
+ typedef int32_t Inst_t;
+ Inst_t *inst = (Inst_t *)&(*text)[rel->getOffset()];
+ Inst_t P = (Inst_t)(uintptr_t)inst;
+ Inst_t A = (Inst_t)(uintptr_t)*inst;
+ Inst_t S = (Inst_t)(uintptr_t)sym->getAddress(EM_MIPS);
+
+ bool need_stub = false;
+
+ if (S == 0 && strcmp (sym->getName(), "_gp_disp") != 0) {
+ need_stub = true;
+ S = (Inst_t)(uintptr_t)find_sym(context, sym->getName());
+ if (!S) {
+ missingSymbols = true;
+ }
+ sym->setAddress((void *)S);
+ }
+
+ switch (rel->getType()) {
+ default:
+ rsl_assert(0 && "Not implemented relocation type.");
+ break;
+
+ case R_MIPS_NONE:
+ case R_MIPS_JALR: // ignore this
+ break;
+
+ case R_MIPS_16:
+ *inst &= 0xFFFF0000;
+ A = A & 0xFFFF;
+ A = S + (short)A;
+ rsl_assert(A >= -32768 && A <= 32767 && "R_MIPS_16 overflow.");
+ *inst |= (A & 0xFFFF);
+ break;
+
+ case R_MIPS_32:
+ *inst = S + A;
+ break;
+
+ case R_MIPS_26:
+ *inst &= 0xFC000000;
+ if (need_stub == false) {
+ A = (A & 0x3FFFFFF) << 2;
+ if (sym->getBindingAttribute() == STB_LOCAL) { // local binding
+ A |= ((P + 4) & 0xF0000000);
+ A += S;
+ *inst |= ((A >> 2) & 0x3FFFFFF);
+ } else { // external binding
+ if (A & 0x08000000) // Sign extend from bit 27
+ A |= 0xF0000000;
+ A += S;
+ *inst |= ((A >> 2) & 0x3FFFFFF);
+ if (((P + 4) >> 28) != (A >> 28)) { // far local call
+ void *stub = text->getStubLayout()->allocateStub((void *)A);
+ rsl_assert(stub && "cannot allocate stub.");
+ sym->setAddress(stub);
+ S = (int32_t)(intptr_t)stub;
+ *inst |= ((S >> 2) & 0x3FFFFFF);
+ rsl_assert(((P + 4) >> 28) == (S >> 28) && "stub is too far.");
+ }
+ }
+ } else { // shared-library call
+ A = (A & 0x3FFFFFF) << 2;
+ rsl_assert(A == 0 && "R_MIPS_26 addend is not zero.");
+ void *stub = text->getStubLayout()->allocateStub((void *)S);
+ rsl_assert(stub && "cannot allocate stub.");
+ sym->setAddress(stub);
+ S = (int32_t)(intptr_t)stub;
+ *inst |= ((S >> 2) & 0x3FFFFFF);
+ rsl_assert(((P + 4) >> 28) == (S >> 28) && "stub is too far.");
+ }
+ break;
+
+ case R_MIPS_HI16:
+ *inst &= 0xFFFF0000;
+ A = (A & 0xFFFF) << 16;
+ // Find the nearest LO16 relocation type after this entry
+ for (size_t j = i + 1; j < reltab->size(); j++) {
+ ELFRelocTy *this_rel = (*reltab)[j];
+ ELFSymbolTy *this_sym = (*symtab)[this_rel->getSymTabIndex()];
+ if (this_rel->getType() == R_MIPS_LO16 && this_sym == sym) {
+ Inst_t *this_inst = (Inst_t *)&(*text)[this_rel->getOffset()];
+ Inst_t this_A = (Inst_t)(uintptr_t)*this_inst;
+ this_A = this_A & 0xFFFF;
+ A += (short)this_A;
+ break;
+ }
+ }
+ if (strcmp (sym->getName(), "_gp_disp") == 0) {
+ S = (int)(intptr_t)got_address() + GP_OFFSET - (int)P;
+ sym->setAddress((void *)S);
+ }
+ *inst |= (((S + A + (int)0x8000) >> 16) & 0xFFFF);
+ break;
+
+ case R_MIPS_LO16:
+ *inst &= 0xFFFF0000;
+ A = A & 0xFFFF;
+ if (strcmp (sym->getName(), "_gp_disp") == 0) {
+ S = (Inst_t)(intptr_t)sym->getAddress(EM_MIPS);
+ }
+ *inst |= ((S + A) & 0xFFFF);
+ break;
+
+ case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
+ {
+ *inst &= 0xFFFF0000;
+ A = A & 0xFFFF;
+ if (rel->getType() == R_MIPS_GOT16) {
+ if (sym->getBindingAttribute() == STB_LOCAL) {
+ A <<= 16;
+
+ // Find the nearest LO16 relocation type after this entry
+ for (size_t j = i + 1; j < reltab->size(); j++) {
+ ELFRelocTy *this_rel = (*reltab)[j];
+ ELFSymbolTy *this_sym = (*symtab)[this_rel->getSymTabIndex()];
+ if (this_rel->getType() == R_MIPS_LO16 && this_sym == sym) {
+ Inst_t *this_inst = (Inst_t *)&(*text)[this_rel->getOffset()];
+ Inst_t this_A = (Inst_t)(uintptr_t)*this_inst;
+ this_A = this_A & 0xFFFF;
+ A += (short)this_A;
+ break;
+ }
+ }
+ } else {
+ rsl_assert(A == 0 && "R_MIPS_GOT16 addend is not 0.");
+ }
+ } else { // R_MIPS_CALL16
+ rsl_assert(A == 0 && "R_MIPS_CALL16 addend is not 0.");
+ }
+ int got_index = search_got((int)rel->getSymTabIndex(), (void *)(S + A),
+ sym->getBindingAttribute());
+ int got_offset = (got_index << 2) - GP_OFFSET;
+ *inst |= (got_offset & 0xFFFF);
+ }
+ break;
+
+ case R_MIPS_GPREL32:
+ *inst = A + S - ((int)(intptr_t)got_address() + GP_OFFSET);
+ break;
+ }
+ }
+}
+
+
+// TODO: Refactor all relocations.
+template <unsigned Bitwidth>
+inline void ELFObject<Bitwidth>::
+relocate(void *(*find_sym)(void *context, char const *name), void *context) {
+ // Init SHNCommonDataSize.
+ // Need refactoring
+ size_t SHNCommonDataSize = 0;
+
+ ELFSectionSymTabTy *symtab =
+ static_cast<ELFSectionSymTabTy *>(getSectionByName(".symtab"));
+ rsl_assert(symtab && "Symtab is required.");
+
+ for (size_t i = 0; i < symtab->size(); ++i) {
+ ELFSymbolTy *sym = (*symtab)[i];
+
+ if (sym->getType() != STT_OBJECT) {
+ continue;
+ }
+
+ size_t idx = (size_t)sym->getSectionIndex();
+ switch (idx) {
+ default:
+ if ((*shtab)[idx]->getType() == SHT_NOBITS) {
+ // FIXME(logan): This is a workaround for .lcomm directives
+ // bug of LLVM ARM MC code generator. Remove this when the
+ // LLVM bug is fixed.
+
+ size_t align = 16;
+ SHNCommonDataSize += (size_t)sym->getSize() + align;
+ }
+ break;
+
+ case SHN_COMMON:
+ {
+ size_t align = (size_t)sym->getValue();
+ SHNCommonDataSize += (size_t)sym->getSize() + align;
+ }
+ break;
+
+ case SHN_ABS:
+ case SHN_UNDEF:
+ case SHN_XINDEX:
+ break;
+ }
+ }
+ if (!initSHNCommonDataSize(SHNCommonDataSize)) {
+ rsl_assert("Allocate memory for common variable fail!");
+ // TODO: Refactor object loading to use proper status/error returns.
+ // We mark the object as having missing symbols and return early in this
+ // case to signal a loading error (usually due to running out of
+ // available memory to allocate).
+ missingSymbols = true;
+ return;
+ }
+
+ for (size_t i = 0; i < stab.size(); ++i) {
+ ELFSectionHeaderTy *sh = (*shtab)[i];
+ if (sh->getType() != SHT_REL && sh->getType() != SHT_RELA) {
+ continue;
+ }
+ ELFSectionRelTableTy *reltab =
+ static_cast<ELFSectionRelTableTy *>(stab[i]);
+ rsl_assert(reltab && "Relocation section can't be NULL.");
+
+ const char *reltab_name = sh->getName();
+ const char *need_rel_name;
+ if (sh->getType() == SHT_REL) {
+ need_rel_name = reltab_name + 4;
+ // ".rel.xxxx"
+ // ^ start from here.
+ } else {
+ need_rel_name = reltab_name + 5;
+ }
+
+ ELFSectionProgBitsTy *need_rel =
+ static_cast<ELFSectionProgBitsTy *>(getSectionByName(need_rel_name));
+ rsl_assert(need_rel && "Need be relocated section can't be NULL.");
+
+ switch (getHeader()->getMachine()) {
+ case EM_ARM:
+ relocateARM(find_sym, context, reltab, need_rel);
+ break;
+ case EM_386:
+ relocateX86_32(find_sym, context, reltab, need_rel);
+ break;
+ case EM_X86_64:
+ relocateX86_64(find_sym, context, reltab, need_rel);
+ break;
+ case EM_MIPS:
+ relocateMIPS(find_sym, context, reltab, need_rel);
+ break;
+
+ default:
+ rsl_assert(0 && "Only support ARM, MIPS, X86, and X86_64 relocation.");
+ break;
+ }
+ }
+
+ for (size_t i = 0; i < stab.size(); ++i) {
+ ELFSectionHeaderTy *sh = (*shtab)[i];
+ if (sh->getType() == SHT_PROGBITS || sh->getType() == SHT_NOBITS) {
+ if (stab[i]) {
+ static_cast<ELFSectionBitsTy *>(stab[i])->protect();
+ }
+ }
+ }
+}
+
+template <unsigned Bitwidth>
+inline void ELFObject<Bitwidth>::print() const {
+ header->print();
+ shtab->print();
+
+ for (size_t i = 0; i < stab.size(); ++i) {
+ ELFSectionTy *sec = stab[i];
+ if (sec) {
+ sec->print();
+ }
+ }
+}
+
+#endif // ELF_OBJECT_HXX
diff --git a/driver/linkloader/include/impl/ELFReloc.hxx b/driver/linkloader/include/impl/ELFReloc.hxx
new file mode 100644
index 0000000..6b55e02
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFReloc.hxx
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_RELOC_HXX
+#define ELF_RELOC_HXX
+
+#include "utils/raw_ostream.h"
+
+#include <llvm/Support/Format.h>
+#include <llvm/Support/raw_ostream.h>
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+inline ELFReloc<Bitwidth> *
+ELFReloc_CRTP<Bitwidth>::readRela(Archiver &AR, size_t index) {
+ if (!AR) {
+ // Archiver is in bad state before calling read function.
+ // Return NULL and do nothing.
+ return 0;
+ }
+
+ llvm::OwningPtr<ELFRelocTy> sh(new ELFRelocTy());
+
+ if (!sh->serializeRela(AR)) {
+ // Unable to read the structure. Return NULL.
+ return 0;
+ }
+
+ if (!sh->isValid()) {
+ // Rel read from archiver is not valid. Return NULL.
+ return 0;
+ }
+
+ // Set the section header index
+ sh->index = index;
+
+ return sh.take();
+}
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+inline ELFReloc<Bitwidth> *
+ELFReloc_CRTP<Bitwidth>::readRel(Archiver &AR, size_t index) {
+ if (!AR) {
+ // Archiver is in bad state before calling read function.
+ // Return NULL and do nothing.
+ return 0;
+ }
+
+ llvm::OwningPtr<ELFRelocTy> sh(new ELFRelocTy());
+
+ sh->r_addend = 0;
+ if (!sh->serializeRel(AR)) {
+ return 0;
+ }
+
+ if (!sh->isValid()) {
+ // Rel read from archiver is not valid. Return NULL.
+ return 0;
+ }
+
+ // Set the section header index
+ sh->index = index;
+
+ return sh.take();
+}
+
+template <unsigned Bitwidth>
+inline void ELFReloc_CRTP<Bitwidth>::print(bool shouldPrintHeader) const {
+ using namespace llvm;
+ if (shouldPrintHeader) {
+ out() << '\n' << fillformat('=', 79) << '\n';
+ out().changeColor(raw_ostream::WHITE, true);
+ out() << "ELF Relaocation Table Entry "
+ << this->getIndex() << '\n';
+ out().resetColor();
+ out() << fillformat('-', 79) << '\n';
+ } else {
+ out() << fillformat('-', 79) << '\n';
+ out().changeColor(raw_ostream::YELLOW, true);
+ out() << "ELF Relaocation Table Entry "
+ << this->getIndex() << " : " << '\n';
+ out().resetColor();
+ }
+
+#define PRINT_LINT(title, value) \
+ out() << format(" %-13s : ", (char const *)(title)) << (value) << '\n'
+ PRINT_LINT("Offset", concrete()->getOffset() );
+ PRINT_LINT("SymTab Index", concrete()->getSymTabIndex() );
+ PRINT_LINT("Type", concrete()->getType() );
+ PRINT_LINT("Addend", concrete()->getAddend() );
+#undef PRINT_LINT
+}
+
+#endif // ELF_RELOC_HXX
diff --git a/driver/linkloader/include/impl/ELFSection.hxx b/driver/linkloader/include/impl/ELFSection.hxx
new file mode 100644
index 0000000..fb0e6f6
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFSection.hxx
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_HXX
+#define ELF_SECTION_HXX
+
+#include "utils/raw_ostream.h"
+
+#include <llvm/Support/raw_ostream.h>
+
+#include "ELFSectionHeader.h"
+#include "ELFSectionStrTab.h"
+#include "ELFSectionSymTab.h"
+#include "ELFSectionProgBits.h"
+#include "ELFSectionNoBits.h"
+#include "ELFSectionRelTable.h"
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+inline ELFSection<Bitwidth> *
+ELFSection<Bitwidth>::read(Archiver &AR,
+ ELFObjectTy *owner,
+ ELFSectionHeaderTy const *sh) {
+ using namespace std;
+
+ switch (sh->getType()) {
+ default:
+ // Uknown type of ELF section. Return NULL.
+ //llvm::errs() << "WARNING: Unknown section type.\n";
+ return 0;
+
+ case SHT_STRTAB:
+ return ELFSectionStrTabTy::read(AR, sh);
+
+ case SHT_SYMTAB:
+ return ELFSectionSymTabTy::read(AR, owner, sh);
+
+ case SHT_PROGBITS:
+ return ELFSectionProgBitsTy::read(AR, owner, sh);
+
+ case SHT_NOBITS:
+ return ELFSectionNoBitsTy::read(AR, sh);
+
+ case SHT_REL:
+ case SHT_RELA:
+ return ELFSectionRelTableTy::read(AR, sh);
+
+ case SHT_NULL:
+ // TODO: Not Yet Implemented
+ return 0;
+ };
+}
+
+#endif // ELF_SECTION_HXX
diff --git a/driver/linkloader/include/impl/ELFSectionBits.hxx b/driver/linkloader/include/impl/ELFSectionBits.hxx
new file mode 100644
index 0000000..bd585d4
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFSectionBits.hxx
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_BITS_HXX
+#define ELF_SECTION_BITS_HXX
+
+#include "utils/flush_cpu_cache.h"
+#include "utils/helper.h"
+
+#include <llvm/Support/raw_ostream.h>
+
+#include <sys/mman.h>
+
+template <unsigned Bitwidth>
+inline void ELFSectionBits<Bitwidth>::print() const {
+ using namespace llvm;
+
+ char const *section_type_str =
+ (sh->getType() == SHT_NOBITS) ? "NOBITS" : "PROGBITS";
+
+ out() << '\n' << fillformat('=', 79) << '\n';
+ out().changeColor(raw_ostream::WHITE, true);
+ out() << "ELF " << section_type_str << ": " << sh->getName() << '\n';
+ out().resetColor();
+ out() << fillformat('-', 79) << '\n';
+
+ out() << " Size : " << sh->getSize() << '\n';
+ out() << " Start Address: " << (void *)chunk.getBuffer() << '\n';
+ out() << fillformat('-', 79) << '\n';
+
+ chunk.print();
+
+ out() << fillformat('=', 79) << '\n';
+}
+
+template <unsigned Bitwidth>
+inline bool ELFSectionBits<Bitwidth>::protect() {
+ int prot = PROT_READ;
+
+ if (sh->getFlags() & SHF_WRITE) {
+ prot |= PROT_WRITE;
+ }
+
+ if (sh->getFlags() & SHF_EXECINSTR) {
+ prot |= PROT_EXEC;
+ }
+
+ return chunk.protect(prot);
+}
+
+#endif // ELF_SECTION_BITS_HXX
diff --git a/driver/linkloader/include/impl/ELFSectionHeader.hxx b/driver/linkloader/include/impl/ELFSectionHeader.hxx
new file mode 100644
index 0000000..78a5495
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFSectionHeader.hxx
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_HEADER_HXX
+#define ELF_SECTION_HEADER_HXX
+
+#include "utils/raw_ostream.h"
+#include <llvm/Support/Format.h>
+#include <llvm/Support/raw_ostream.h>
+
+#include "ELFObject.h"
+
+template <unsigned Bitwidth>
+char const *ELFSectionHeader_CRTP<Bitwidth>::getName() const {
+ return owner->getSectionName(getNameIndex());
+}
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+typename ELFSectionHeader_CRTP<Bitwidth>::ELFSectionHeaderTy *
+ELFSectionHeader_CRTP<Bitwidth>::read(Archiver &AR,
+ ELFObjectTy const *owner,
+ size_t index) {
+
+ if (!AR) {
+ // Archiver is in bad state before calling read function.
+ // Return NULL and do nothing.
+ return 0;
+ }
+
+ llvm::OwningPtr<ELFSectionHeaderTy> sh(new ELFSectionHeaderTy());
+
+ if (!sh->serialize(AR)) {
+ // Unable to read the structure. Return NULL.
+ return 0;
+ }
+
+ if (!sh->isValid()) {
+ // Header read from archiver is not valid. Return NULL.
+ return 0;
+ }
+
+ // Set the section header index
+ sh->index = index;
+
+ // Set the owner elf object
+ sh->owner = owner;
+
+ return sh.take();
+}
+
+template <unsigned Bitwidth>
+void ELFSectionHeader_CRTP<Bitwidth>::print(bool shouldPrintHeader) const {
+ using namespace llvm;
+
+ if (shouldPrintHeader) {
+ out() << '\n' << fillformat('=', 79) << '\n';
+ out().changeColor(raw_ostream::WHITE, true);
+ out() << "ELF Section Header "
+ << this->getIndex() << '\n';
+ out().resetColor();
+ out() << fillformat('-', 79) << '\n';
+ } else {
+ out() << fillformat('-', 79) << '\n';
+ out().changeColor(raw_ostream::YELLOW, true);
+ out() << "ELF Section Header "
+ << this->getIndex() << " : " << '\n';
+ out().resetColor();
+ }
+
+#define PRINT_LINT(title, value) \
+ out() << format(" %-13s : ", (char const *)(title)) << (value) << '\n'
+ PRINT_LINT("Name", getName() );
+ PRINT_LINT("Type", getSectionTypeStr(getType()));
+ PRINT_LINT("Flags", concrete()->getFlags());
+ PRINT_LINT("Address", getAddress());
+ PRINT_LINT("Offset", getOffset());
+ PRINT_LINT("Size", concrete()->getSize());
+ PRINT_LINT("Link", getLink());
+ PRINT_LINT("Extra Info", getExtraInfo());
+ PRINT_LINT("Address Align", concrete()->getAddressAlign());
+ PRINT_LINT("Entry Size", concrete()->getEntrySize());
+#undef PRINT_LINT
+
+ if (shouldPrintHeader) {
+ out() << fillformat('=', 79) << '\n';
+ }
+}
+
+#endif // ELF_SECTION_HEADER_HXX
diff --git a/driver/linkloader/include/impl/ELFSectionHeaderTable.hxx b/driver/linkloader/include/impl/ELFSectionHeaderTable.hxx
new file mode 100644
index 0000000..1f693a4
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFSectionHeaderTable.hxx
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_HEADER_TABLE_HXX
+#define ELF_SECTION_HEADER_TABLE_HXX
+
+#include "ELFHeader.h"
+#include "ELFObject.h"
+#include "ELFSectionHeader.h"
+
+#include "utils/rsl_assert.h"
+
+template <unsigned Bitwidth>
+ELFSectionHeaderTable<Bitwidth>::~ELFSectionHeaderTable() {
+ for (size_t i = 0; i < table.size(); ++i) {
+ delete table[i];
+ }
+}
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+inline ELFSectionHeaderTable<Bitwidth> *
+ELFSectionHeaderTable<Bitwidth>::read(Archiver &AR, ELFObjectTy *owner) {
+ if (!AR) {
+ // Archiver is in bad state before calling read function.
+ // Return NULL and do nothing.
+ return 0;
+ }
+
+ // Allocate a new section header table and assign the owner.
+ llvm::OwningPtr<ELFSectionHeaderTable> tab(new ELFSectionHeaderTable());
+
+ // Get ELF header
+ ELFHeaderTy const *header = owner->getHeader();
+
+ rsl_assert(header->getSectionHeaderEntrySize() ==
+ TypeTraits<ELFSectionHeaderTy>::size);
+
+ // Seek to the address of section header
+ AR.seek(header->getSectionHeaderTableOffset(), true);
+
+ for (size_t i = 0; i < header->getSectionHeaderNum(); ++i) {
+ llvm::OwningPtr<ELFSectionHeaderTy> sh(
+ ELFSectionHeaderTy::read(AR, owner, i));
+
+ if (!sh) {
+ // Something wrong while reading the section header.
+ return 0;
+ }
+
+ tab->table.push_back(sh.take());
+ }
+
+ return tab.take();
+}
+
+template <unsigned Bitwidth>
+inline void ELFSectionHeaderTable<Bitwidth>::print() const {
+ using namespace llvm;
+
+ out() << '\n' << fillformat('=', 79) << '\n';
+ out().changeColor(raw_ostream::WHITE, true);
+ out() << "ELF Section Header Table" << '\n';
+ out().resetColor();
+
+ for (size_t i = 0; i < table.size(); ++i) {
+ (*this)[i]->print();
+ }
+
+ out() << fillformat('=', 79) << '\n';
+}
+
+template <unsigned Bitwidth>
+inline void ELFSectionHeaderTable<Bitwidth>::buildNameMap() {
+ for (size_t i = 0; i < table.size(); ++i) {
+ ELFSectionHeaderTy *sh = table[i];
+ if ( sh ) {
+ name_map[sh->getName()] = sh;
+ }
+ }
+}
+
+template <unsigned Bitwidth>
+inline ELFSectionHeader<Bitwidth> const *
+ELFSectionHeaderTable<Bitwidth>::getByName(const std::string &name) const {
+ typename llvm::StringMap<ELFSectionHeaderTy *>::const_iterator sh =
+ name_map.find(name);
+ if (sh == name_map.end()) {
+ // Return SHN_UNDEF section header;
+ return table[0];
+ }
+ return sh->getValue();
+}
+
+template <unsigned Bitwidth>
+inline ELFSectionHeader<Bitwidth> *
+ELFSectionHeaderTable<Bitwidth>::getByName(const std::string &name) {
+ ELFSectionHeaderTableTy const *const_this = this;
+ ELFSectionHeaderTy const *shptr = const_this->getByName(name);
+ // Const cast for the same API's const and non-const versions.
+ return const_cast<ELFSectionHeaderTy *>(shptr);
+}
+
+#endif // ELF_SECTION_HEADER_TABLE_HXX
diff --git a/driver/linkloader/include/impl/ELFSectionNoBits.hxx b/driver/linkloader/include/impl/ELFSectionNoBits.hxx
new file mode 100644
index 0000000..d1a6436
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFSectionNoBits.hxx
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_NOBITS_HXX
+#define ELF_SECTION_NOBITS_HXX
+
+#include "ELFTypes.h"
+
+#include "utils/raw_ostream.h"
+
+#include <llvm/Support/Format.h>
+#include <llvm/Support/raw_ostream.h>
+
+#include <sys/mman.h>
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+inline ELFSectionNoBits<Bitwidth> *
+ELFSectionNoBits<Bitwidth>::read(Archiver &AR, ELFSectionHeaderTy const *sh) {
+ llvm::OwningPtr<ELFSectionNoBits> result(new ELFSectionNoBits());
+
+ if (!result->chunk.allocate(sh->getSize())) {
+ return NULL;
+ }
+
+ result->sh = sh;
+
+ return result.take();
+}
+
+#endif // ELF_SECTION_NOBITS_HXX
diff --git a/driver/linkloader/include/impl/ELFSectionProgBits.hxx b/driver/linkloader/include/impl/ELFSectionProgBits.hxx
new file mode 100644
index 0000000..434e5b5
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFSectionProgBits.hxx
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_PROGBITS_HXX
+#define ELF_SECTION_PROGBITS_HXX
+
+#include "ELFTypes.h"
+#include "StubLayout.h"
+
+#include <llvm/Support/Format.h>
+#include <llvm/Support/raw_ostream.h>
+
+#include "utils/raw_ostream.h"
+
+#include <string.h>
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+ELFSectionProgBits<Bitwidth> *
+ELFSectionProgBits<Bitwidth>::read(Archiver &AR,
+ ELFObjectTy *owner,
+ ELFSectionHeaderTy const *sh) {
+ int machine = owner->getHeader()->getMachine();
+ ELFSectionProgBits *secp = new ELFSectionProgBits(machine);
+ llvm::OwningPtr<ELFSectionProgBits> result(secp);
+ size_t max_num_stubs = 0;
+ // Align section boundary to 4 bytes.
+ size_t section_size = (sh->getSize() + 3) / 4 * 4;
+ size_t alloc_size = section_size;
+ StubLayout *stubs = result->getStubLayout();
+ if (stubs) {
+ // Compute the maximal possible numbers of stubs
+ std::string reltab_name(".rel" + std::string(sh->getName()));
+
+ ELFSectionRelTableTy const *reltab =
+ static_cast<ELFSectionRelTableTy *>(
+ owner->getSectionByName(reltab_name.c_str()));
+
+ if (reltab) {
+ // If we have relocation table, then get the approximation of
+ // maximum numbers of stubs.
+ max_num_stubs = reltab->getMaxNumStubs(owner);
+ }
+
+ // Compute the stub table size
+ size_t stub_table_size = stubs->calcStubTableSize(max_num_stubs);
+
+ // Allocate PROGBITS section with stubs table
+ alloc_size += stub_table_size;
+ }
+
+ // Allocate text section
+ if (!result->chunk.allocate(alloc_size)) {
+ return NULL;
+ }
+
+ if (stubs) {
+ stubs->initStubTable(result->chunk.getBuffer() + section_size,
+ max_num_stubs);
+ }
+
+ result->sh = sh;
+
+ if (!result->serialize(AR)) {
+ // Unable to read the progbits section.
+ return NULL;
+ }
+
+ return result.take();
+}
+
+#endif // ELF_SECTION_PROGBITS_HXX
diff --git a/driver/linkloader/include/impl/ELFSectionRelTable.hxx b/driver/linkloader/include/impl/ELFSectionRelTable.hxx
new file mode 100644
index 0000000..c6c4dde
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFSectionRelTable.hxx
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_REL_TABLE_HXX
+#define ELF_SECTION_REL_TABLE_HXX
+
+#include "ELF.h"
+#include "ELFHeader.h"
+#include "ELFObject.h"
+#include "ELFReloc.h"
+#include "ELFTypes.h"
+
+#include <set>
+
+template <unsigned Bitwidth>
+ELFSectionRelTable<Bitwidth>::~ELFSectionRelTable() {
+ using namespace std;
+ for (size_t i = 0; i < table.size(); ++i) {
+ delete table[i];
+ }
+}
+
+template <unsigned Bitwidth>
+void ELFSectionRelTable<Bitwidth>::print() const {
+ using namespace llvm;
+
+ out() << '\n' << fillformat('=', 79) << '\n';
+ out().changeColor(raw_ostream::WHITE, true);
+ out() << "Relocation Table" << '\n';
+ out().resetColor();
+
+ for (size_t i = 0; i < this->size(); ++i) {
+ (*this)[i]->print();
+ }
+
+ out() << fillformat('=', 79) << '\n';
+}
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+ELFSectionRelTable<Bitwidth> *
+ELFSectionRelTable<Bitwidth>::read(Archiver &AR,
+ ELFSectionHeaderTy const *sh) {
+
+ rsl_assert(sh->getType() == SHT_REL || sh->getType() == SHT_RELA);
+
+ llvm::OwningPtr<ELFSectionRelTable> rt(new ELFSectionRelTable());
+
+ // Seek to the start of the table
+ AR.seek(sh->getOffset(), true);
+
+ // Count the relocation entries
+ size_t size = sh->getSize() / sh->getEntrySize();
+
+ // Read every relocation entries
+ if (sh->getType() == SHT_REL) {
+ rsl_assert(sh->getEntrySize() == TypeTraits<ELFRelocRelTy>::size);
+ for (size_t i = 0; i < size; ++i) {
+ rt->table.push_back(ELFRelocTy::readRel(AR, i));
+ }
+
+ } else {
+ rsl_assert(sh->getEntrySize() == TypeTraits<ELFRelocRelaTy>::size);
+ for (size_t i = 0; i < size; ++i) {
+ rt->table.push_back(ELFRelocTy::readRela(AR, i));
+ }
+ }
+
+ if (!AR) {
+ // Unable to read the table.
+ return 0;
+ }
+
+ return rt.take();
+}
+
+template <unsigned Bitwidth>
+size_t ELFSectionRelTable<Bitwidth>::
+getMaxNumStubs(ELFObjectTy const *obj) const {
+ switch (obj->getHeader()->getMachine()) {
+ case EM_ARM:
+ {
+ std::set<uint32_t> sym_index_set;
+
+ for (size_t i = 0; i < size(); ++i) {
+ ELFRelocTy *rel = table[i];
+
+ switch (rel->getType()) {
+ case R_ARM_CALL:
+ case R_ARM_THM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_THM_JUMP24:
+ sym_index_set.insert(rel->getSymTabIndex());
+ break;
+ }
+ }
+
+ return sym_index_set.size();
+ }
+
+ case EM_MIPS:
+ {
+ std::set<uint32_t> sym_index_set;
+
+ for (size_t i = 0; i < size(); ++i) {
+ ELFRelocTy *rel = table[i];
+
+ if (rel->getType() == R_MIPS_26) {
+ sym_index_set.insert(rel->getSymTabIndex());
+ }
+ }
+
+ return sym_index_set.size();
+ }
+
+ case EM_386:
+ case EM_X86_64:
+ return 0;
+
+ default:
+ rsl_assert(0 && "Only support ARM, MIPS, X86, and X86_64 relocation.");
+ return 0;
+ }
+}
+
+#endif // ELF_SECTION_REL_TABLE_HXX
diff --git a/driver/linkloader/include/impl/ELFSectionStrTab.hxx b/driver/linkloader/include/impl/ELFSectionStrTab.hxx
new file mode 100644
index 0000000..4e9eb4e
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFSectionStrTab.hxx
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_STR_TAB_HXX
+#define ELF_SECTION_STR_TAB_HXX
+
+#include "utils/helper.h"
+#include "utils/raw_ostream.h"
+
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/Support/Format.h>
+#include <llvm/Support/raw_ostream.h>
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+ELFSectionStrTab<Bitwidth> *
+ELFSectionStrTab<Bitwidth>::read(Archiver &AR,
+ ELFSectionHeaderTy const *sh) {
+
+ llvm::OwningPtr<ELFSectionStrTab> st(new ELFSectionStrTab());
+ st->buf.resize(sh->getSize());
+
+ // Save section_header
+ st->section_header = sh;
+
+ AR.seek(sh->getOffset(), true);
+ AR.prologue(sh->getSize());
+ AR.readBytes(&*st->buf.begin(), sh->getSize());
+ AR.epilogue(sh->getSize());
+
+ if (!AR) {
+ // Unable to read the string table.
+ return 0;
+ }
+
+ return st.take();
+}
+
+template <unsigned Bitwidth>
+void ELFSectionStrTab<Bitwidth>::print() const {
+ using namespace llvm;
+
+ out() << '\n' << fillformat('=', 79) << '\n';
+ out().changeColor(raw_ostream::WHITE, true);
+ out() << "ELF String Table: " << this->section_header->getName() << '\n';
+ out().resetColor();
+ out() << fillformat('-', 79) << '\n';
+
+ dump_hex((unsigned char const *)&*buf.begin(), buf.size(), 0, buf.size());
+
+ out() << fillformat('=', 79) << '\n';
+}
+
+#endif // ELF_SECTION_STR_TAB_HXX
diff --git a/driver/linkloader/include/impl/ELFSectionSymTab.hxx b/driver/linkloader/include/impl/ELFSectionSymTab.hxx
new file mode 100644
index 0000000..b179383
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFSectionSymTab.hxx
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SECTION_SYM_TAB_HXX
+#define ELF_SECTION_SYM_TAB_HXX
+
+#include "ELFSectionHeader.h"
+#include "ELFSymbol.h"
+#include "utils/rsl_assert.h"
+
+template <unsigned Bitwidth>
+ELFSectionSymTab<Bitwidth>::~ELFSectionSymTab() {
+ for (size_t i = 0; i < table.size(); ++i) {
+ delete table[i];
+ }
+}
+
+template <unsigned Bitwidth>
+size_t ELFSectionSymTab<Bitwidth>::getFuncCount() const {
+ size_t result = 0;
+ for (size_t i = 0; i < table.size(); ++i) {
+ if (table[i] && table[i]->isConcreteFunc()) {
+ result++;
+ }
+ }
+ return result;
+}
+
+template <unsigned Bitwidth>
+inline size_t ELFSectionSymTab<Bitwidth>::getExternFuncCount() const {
+ size_t result = 0;
+ for (size_t i = 0; i < table.size(); ++i) {
+ if (table[i] && table[i]->isExternFunc()) {
+ result++;
+ }
+ }
+ return result;
+}
+
+template <unsigned Bitwidth>
+inline void ELFSectionSymTab<Bitwidth>::buildNameMap() {
+ for (size_t i = 0; i < table.size(); ++i) {
+ ELFSymbolTy *symbol = table[i];
+ if ( symbol ) {
+ name_map[symbol->getName()] = symbol;
+ }
+ }
+}
+
+template <unsigned Bitwidth>
+inline ELFSymbol<Bitwidth> const *
+ELFSectionSymTab<Bitwidth>::getByName(std::string const &name) const {
+ typename llvm::StringMap<ELFSymbolTy *>::const_iterator symbol =
+ name_map.find(name);
+ if (symbol == name_map.end()) {
+ return NULL;
+ }
+ return symbol->getValue();
+}
+
+template <unsigned Bitwidth>
+inline void
+ELFSectionSymTab<Bitwidth>::getFuncNameList(size_t size,
+ char const **list) const {
+ for (size_t i = 0, j = 0; i < table.size() && j < size; ++i) {
+ if (table[i] && table[i]->isConcreteFunc()) {
+ list[j++] = table[i]->getName();
+ }
+ }
+}
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+ELFSectionSymTab<Bitwidth> *
+ELFSectionSymTab<Bitwidth>::read(Archiver &AR,
+ ELFObjectTy *owner,
+ ELFSectionHeaderTy const *sh) {
+
+ llvm::OwningPtr<ELFSectionSymTabTy> st(new ELFSectionSymTabTy());
+
+ // Assert that entry size will be the same as standard.
+ rsl_assert(sh->getEntrySize() == TypeTraits<ELFSymbolTy>::size);
+
+ // Seek to the start of symbol table
+ AR.seek(sh->getOffset(), true);
+
+ // Read all symbol table entry
+ size_t size = sh->getSize() / sh->getEntrySize();
+ for (size_t i = 0; i < size; ++i) {
+ st->table.push_back(ELFSymbolTy::read(AR, owner, i));
+ }
+
+ if (!AR) {
+ // Unable to read the table.
+ return 0;
+ }
+
+ return st.take();
+}
+
+template <unsigned Bitwidth>
+void ELFSectionSymTab<Bitwidth>::print() const {
+ using namespace llvm;
+
+ out() << '\n' << fillformat('=', 79) << '\n';
+ out().changeColor(raw_ostream::WHITE, true);
+ out() << "Symbol Table" << '\n';
+ out().resetColor();
+
+ for (size_t i = 0; i < table.size(); ++i) {
+ table[i]->print();
+ }
+
+ out() << fillformat('=', 79) << '\n';
+}
+
+#endif // ELF_SECTION_SYM_TAB_HXX
diff --git a/driver/linkloader/include/impl/ELFSymbol.hxx b/driver/linkloader/include/impl/ELFSymbol.hxx
new file mode 100644
index 0000000..b3c6087
--- /dev/null
+++ b/driver/linkloader/include/impl/ELFSymbol.hxx
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_SYMBOL_HXX
+#define ELF_SYMBOL_HXX
+
+#include "ELFSectionHeaderTable.h"
+#include "ELFSection.h"
+#include "ELFSectionStrTab.h"
+
+#include "ELFObject.h"
+#include "ELFSectionHeaderTable.h"
+#include "ELFSectionProgBits.h"
+#include "ELFSectionNoBits.h"
+
+#include "utils/rsl_assert.h"
+#include "ELF.h"
+
+template <unsigned Bitwidth>
+inline char const *ELFSymbol_CRTP<Bitwidth>::getName() const {
+ ELFSectionHeaderTableTy const &shtab = *owner->getSectionHeaderTable();
+ size_t const index = shtab.getByName(std::string(".strtab"))->getIndex();
+ ELFSectionTy const *section = owner->getSectionByIndex(index);
+ ELFSectionStrTabTy const &strtab =
+ *static_cast<ELFSectionStrTabTy const *>(section);
+ return strtab[getNameIndex()];
+}
+
+template <unsigned Bitwidth>
+template <typename Archiver>
+inline ELFSymbol<Bitwidth> *
+ELFSymbol_CRTP<Bitwidth>::read(Archiver &AR,
+ ELFObjectTy const *owner,
+ size_t index) {
+ if (!AR) {
+ // Archiver is in bad state before calling read function.
+ // Return NULL and do nothing.
+ return 0;
+ }
+
+ llvm::OwningPtr<ELFSymbolTy> sh(new ELFSymbolTy());
+
+ if (!sh->serialize(AR)) {
+ // Unable to read the structure. Return NULL.
+ return 0;
+ }
+
+ if (!sh->isValid()) {
+ // SymTabEntry read from archiver is not valid. Return NULL.
+ return 0;
+ }
+
+ // Set the section header index
+ sh->index = index;
+
+ // Set the owner elf object
+ sh->owner = owner;
+
+ return sh.take();
+}
+
+template <unsigned Bitwidth>
+inline void ELFSymbol_CRTP<Bitwidth>::print(bool shouldPrintHeader) const {
+ using namespace llvm;
+
+ if (shouldPrintHeader) {
+ out() << '\n' << fillformat('=', 79) << '\n';
+ out().changeColor(raw_ostream::WHITE, true);
+ out() << "ELF Symbol Table Entry "
+ << this->getIndex() << '\n';
+ out().resetColor();
+ out() << fillformat('-', 79) << '\n';
+ } else {
+ out() << fillformat('-', 79) << '\n';
+ out().changeColor(raw_ostream::YELLOW, true);
+ out() << "ELF Symbol Table Entry "
+ << this->getIndex() << " : " << '\n';
+ out().resetColor();
+ }
+
+#define PRINT_LINT(title, value) \
+ out() << format(" %-11s : ", (char const *)(title)) << (value) << '\n'
+ PRINT_LINT("Name", getName() );
+ PRINT_LINT("Type", getTypeStr(getType()) );
+ PRINT_LINT("Bind", getBindingAttributeStr(getBindingAttribute()));
+ PRINT_LINT("Visibility", getVisibilityStr(getVisibility()) );
+ PRINT_LINT("Shtab Index", getSectionIndex() );
+ PRINT_LINT("Value", getValue() );
+ PRINT_LINT("Size", getSize() );
+#undef PRINT_LINT
+
+// TODO: Horizontal type or vertical type can use option to decide.
+#if 0
+ using namespace term::color;
+ using namespace std;
+
+ cout << setw(20) << getName() <<
+ setw(10) << getTypeStr(getType()) <<
+ setw(10) << getBindingAttributeStr(getBindingAttribute()) <<
+ setw(15) << getVisibilityStr(getVisibility()) <<
+ setw(10) << getSectionIndex() <<
+ setw(7) << getValue() <<
+ setw(7) << getSize() <<
+ endl;
+#endif
+}
+
+template <unsigned Bitwidth>
+void *ELFSymbol_CRTP<Bitwidth>::getAddress(int machine, bool autoAlloc) const {
+ if (my_addr != 0) {
+ return my_addr;
+ }
+ size_t idx = (size_t)getSectionIndex();
+ switch (getType()) {
+ default:
+ break;
+
+ case STT_OBJECT:
+ switch (idx) {
+ default:
+ {
+ ELFSectionHeaderTableTy const *header =
+ owner->getSectionHeaderTable();
+
+ unsigned section_type = (*header)[idx]->getType();
+
+ rsl_assert((section_type == SHT_PROGBITS ||
+ section_type == SHT_NOBITS) &&
+ "STT_OBJECT with not BITS section.");
+
+ if (section_type == SHT_NOBITS) {
+ // FIXME(logan): This is a workaround for .lcomm directives
+ // bug of LLVM ARM MC code generator. Remove this when the
+ // LLVM bug is fixed.
+
+ size_t align = 16;
+
+ my_addr = const_cast<ELFObjectTy *>(owner)->
+ allocateSHNCommonData((size_t)getSize(), align);
+
+ if (!my_addr) {
+ rsl_assert(0 && "Unable to allocate memory for SHN_COMMON.");
+ abort();
+ }
+ } else {
+ ELFSectionTy const *sec = owner->getSectionByIndex(idx);
+ rsl_assert(sec != 0 && "STT_OBJECT with null section.");
+
+ ELFSectionBitsTy const &st =
+ static_cast<ELFSectionBitsTy const &>(*sec);
+ my_addr =const_cast<unsigned char *>(&st[0] + (off_t)getValue());
+ }
+ }
+ break;
+
+ case SHN_COMMON:
+ {
+ if (!autoAlloc) {
+ return NULL;
+ }
+#if 0
+#if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
+ if (posix_memalign(&my_addr,
+ std::max((size_t)getValue(), sizeof(void*)),
+ (size_t)getSize()) != 0) {
+ rsl_assert(0 && "posix_memalign failed.");
+ }
+#else
+ my_addr = memalign(std::max((size_t)getValue(), sizeof(void *)),
+ (size_t)getSize());
+
+ rsl_assert(my_addr != NULL && "memalign failed.");
+#endif
+ if (my_addr) {
+ memset(my_addr, '\0', getSize());
+ }
+#else
+ size_t align = (size_t)getValue();
+ my_addr = const_cast<ELFObjectTy *>(owner)->
+ allocateSHNCommonData((size_t)getSize(), align);
+ if (!my_addr) {
+ rsl_assert(0 && "Unable to allocate memory for SHN_COMMON.");
+ abort();
+ }
+#endif
+ }
+ break;
+
+ case SHN_UNDEF:
+ if (machine == EM_MIPS && strcmp(getName(), "_gp_disp") == 0) // OK for MIPS
+ break;
+
+ case SHN_ABS:
+ case SHN_XINDEX:
+ rsl_assert(0 && "STT_OBJECT with special st_shndx.");
+ break;
+ }
+ break;
+
+
+ case STT_FUNC:
+ switch (idx) {
+ default:
+ {
+#ifndef NDEBUG
+ ELFSectionHeaderTableTy const *header =
+ owner->getSectionHeaderTable();
+ rsl_assert((*header)[idx]->getType() == SHT_PROGBITS &&
+ "STT_FUNC with not PROGBITS section.");
+#endif
+ ELFSectionTy const *sec = owner->getSectionByIndex(idx);
+ rsl_assert(sec != 0 && "STT_FUNC with null section.");
+
+ ELFSectionProgBitsTy const &st =
+ static_cast<ELFSectionProgBitsTy const &>(*sec);
+ my_addr = const_cast<unsigned char *>(&st[0] + (off_t)getValue());
+ }
+ break;
+
+ case SHN_ABS:
+ case SHN_COMMON:
+ case SHN_UNDEF:
+ case SHN_XINDEX:
+ rsl_assert(0 && "STT_FUNC with special st_shndx.");
+ break;
+ }
+ break;
+
+
+ case STT_SECTION:
+ switch (idx) {
+ default:
+ {
+#ifndef NDEBUG
+ ELFSectionHeaderTableTy const *header =
+ owner->getSectionHeaderTable();
+ rsl_assert(((*header)[idx]->getType() == SHT_PROGBITS ||
+ (*header)[idx]->getType() == SHT_NOBITS) &&
+ "STT_SECTION with not BITS section.");
+#endif
+ ELFSectionTy const *sec = owner->getSectionByIndex(idx);
+ rsl_assert(sec != 0 && "STT_SECTION with null section.");
+
+ ELFSectionBitsTy const &st =
+ static_cast<ELFSectionBitsTy const &>(*sec);
+ my_addr = const_cast<unsigned char *>(&st[0] + (off_t)getValue());
+ }
+ break;
+
+ case SHN_ABS:
+ case SHN_COMMON:
+ case SHN_UNDEF:
+ case SHN_XINDEX:
+ rsl_assert(0 && "STT_SECTION with special st_shndx.");
+ break;
+ }
+ break;
+
+ case STT_NOTYPE:
+ switch (idx) {
+ default:
+ {
+#ifndef NDEBUG
+ ELFSectionHeaderTableTy const *header =
+ owner->getSectionHeaderTable();
+ rsl_assert(((*header)[idx]->getType() == SHT_PROGBITS ||
+ (*header)[idx]->getType() == SHT_NOBITS) &&
+ "STT_SECTION with not BITS section.");
+#endif
+ ELFSectionTy const *sec = owner->getSectionByIndex(idx);
+ rsl_assert(sec != 0 && "STT_SECTION with null section.");
+
+ ELFSectionBitsTy const &st =
+ static_cast<ELFSectionBitsTy const &>(*sec);
+ my_addr = const_cast<unsigned char *>(&st[0] + (off_t)getValue());
+ }
+ break;
+
+ case SHN_ABS:
+ case SHN_COMMON:
+ case SHN_XINDEX:
+ rsl_assert(0 && "STT_SECTION with special st_shndx.");
+ break;
+ case SHN_UNDEF:
+ return 0;
+ }
+ break;
+ return 0;
+
+ case STT_COMMON:
+ case STT_FILE:
+ case STT_TLS:
+ case STT_LOOS:
+ case STT_HIOS:
+ case STT_LOPROC:
+ case STT_HIPROC:
+ rsl_assert(0 && "Not implement.");
+ return 0;
+ }
+ return my_addr;
+}
+
+#endif // ELF_SYMBOL_HXX
diff --git a/driver/linkloader/lib/ELFHeader.cpp b/driver/linkloader/lib/ELFHeader.cpp
new file mode 100644
index 0000000..5e21d3e
--- /dev/null
+++ b/driver/linkloader/lib/ELFHeader.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ELFHeader.h"
+#include "ELF.h"
+
+char const *ELFHeaderHelperMixin::getClassStr(int clazz) {
+ switch (clazz) {
+ default:
+#define CASE_PAIR(A, B) case A: return B;
+ CASE_PAIR(ELFCLASSNONE, "Invalid class")
+ CASE_PAIR(ELFCLASS32, "32bit")
+ CASE_PAIR(ELFCLASS64, "64bit")
+#undef CASE_PAIR
+ }
+}
+
+char const *ELFHeaderHelperMixin::getEndiannessStr(int endianness) {
+ switch (endianness) {
+ default:
+#define CASE_PAIR(A, B) case A: return B;
+ CASE_PAIR(ELFDATANONE, "Invalid endianness")
+ CASE_PAIR(ELFDATA2LSB, "Little endian")
+ CASE_PAIR(ELFDATA2MSB, "Big endian")
+#undef CASE_PAIR
+ }
+}
+
+char const *ELFHeaderHelperMixin::getOSABIStr(int abi) {
+ if (abi >= 64 && abi <= 255) {
+ return "Architecture specific";
+ }
+
+ switch (abi) {
+ default: return "Unknown OS ABI";
+#define CASE_PAIR(A, B) case A: return B;
+ CASE_PAIR(ELFOSABI_NONE, "No extensions or not specified")
+ CASE_PAIR(ELFOSABI_HPUX, "HP-UX")
+ CASE_PAIR(ELFOSABI_NETBSD, "NetBSD")
+ CASE_PAIR(ELFOSABI_LINUX, "Linux")
+ CASE_PAIR(ELFOSABI_SOLARIS, "Solaris")
+ CASE_PAIR(ELFOSABI_AIX, "AIX")
+ CASE_PAIR(ELFOSABI_FREEBSD, "FreeBSD")
+ CASE_PAIR(ELFOSABI_TRU64, "Tru64")
+ CASE_PAIR(ELFOSABI_MODESTO, "Modesto")
+ CASE_PAIR(ELFOSABI_OPENBSD, "OpenBSD")
+#undef CASE_PAIR
+ }
+}
+
+char const *ELFHeaderHelperMixin::getObjectTypeStr(uint16_t type) {
+ switch (type) {
+ default: return "No file type";
+
+ case ET_REL: return "Relocatable file";
+ case ET_EXEC: return "Executable file";
+ case ET_DYN: return "Shared object file";
+ case ET_CORE: return "Core file";
+
+ case ET_LOOS: case ET_HIOS:
+ return "Operating system-specific";
+
+ case ET_LOPROC: case ET_HIPROC:
+ return "Processor-specific";
+ }
+}
+
+char const *ELFHeaderHelperMixin::getMachineStr(uint16_t machine) {
+ switch (machine) {
+ default: return "No machine or unknown";
+ case EM_386: return "Intel 80386 (X86)";
+ case EM_X86_64: return "AMD x86-64 architecture";
+ case EM_ARM: return "Advanced RISC Machine (ARM)";
+ case EM_MIPS: return "MIPS";
+ }
+}
+
+char const *ELFHeaderHelperMixin::getVersionStr(uint32_t version) {
+ switch (version) {
+ default: return "Invalid version";
+ case EV_CURRENT: return "Current version";
+ }
+}
diff --git a/driver/linkloader/lib/ELFSectionHeader.cpp b/driver/linkloader/lib/ELFSectionHeader.cpp
new file mode 100644
index 0000000..03930d6
--- /dev/null
+++ b/driver/linkloader/lib/ELFSectionHeader.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ELFSectionHeader.h"
+#include "ELF.h"
+
+// ARM Section Header Type Definitions
+
+// TODO: These definitions are not defined in external/elfutils/libelf/
+// elf.h. So we to this by ourself. Maybe we should update elf.h
+// instead.
+
+#ifndef SHT_ARM_EXIDX
+#define SHT_ARM_EXIDX (SHT_LOPROC + 1)
+#endif
+
+#ifndef SHT_ARM_PREEMPTMAP
+#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2)
+#endif
+
+#ifndef SHT_ARM_ATTRIBUTES
+#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3)
+#endif
+
+char const *ELFSectionHeaderHelperMixin::getSectionTypeStr(uint32_t type) {
+ switch (type) {
+ default: return "(UNKNOWN)";
+
+#define CASE(TYPE) \
+ case SHT_##TYPE: return #TYPE;
+
+ // General section header type
+ CASE(NULL) CASE(PROGBITS) CASE(SYMTAB) CASE(STRTAB) CASE(RELA) CASE(HASH)
+ CASE(DYNAMIC) CASE(NOTE) CASE(NOBITS) CASE(REL) CASE(SHLIB)
+ CASE(DYNSYM) CASE(INIT_ARRAY) CASE(FINI_ARRAY) CASE(PREINIT_ARRAY)
+ CASE(GROUP) CASE(SYMTAB_SHNDX) CASE(LOOS) CASE(HIOS) CASE(LOPROC)
+ CASE(HIPROC) CASE(LOUSER) CASE(HIUSER)
+
+ // ARM-specific section header type
+ CASE(ARM_EXIDX) CASE(ARM_PREEMPTMAP) CASE(ARM_ATTRIBUTES)
+
+#undef CASE
+ }
+}
diff --git a/driver/linkloader/lib/ELFSymbol.cpp b/driver/linkloader/lib/ELFSymbol.cpp
new file mode 100644
index 0000000..cfdab1c
--- /dev/null
+++ b/driver/linkloader/lib/ELFSymbol.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ELFSymbol.h"
+#include "ELF.h"
+
+char const *
+ELFSymbolHelperMixin::getTypeStr(uint8_t type) {
+ switch (type) {
+ default: return "(UNKNOWN)";
+
+#define CASE(TYPE) \
+ case STT_##TYPE: return #TYPE;
+
+ CASE(NOTYPE)
+ CASE(OBJECT)
+ CASE(FUNC)
+ CASE(SECTION)
+ CASE(FILE)
+ CASE(COMMON)
+ CASE(TLS)
+ CASE(LOOS)
+ CASE(HIOS)
+ CASE(LOPROC)
+ CASE(HIPROC)
+
+#undef CASE
+ }
+}
+
+char const *
+ELFSymbolHelperMixin::getBindingAttributeStr(uint8_t type) {
+ switch (type) {
+ default: return "(UNKNOWN)";
+
+#define CASE(TYPE) \
+ case STB_##TYPE: return #TYPE;
+
+ CASE(LOCAL)
+ CASE(GLOBAL)
+ CASE(WEAK)
+ CASE(LOOS)
+ CASE(HIOS)
+ CASE(LOPROC)
+ CASE(HIPROC)
+
+#undef CASE
+ }
+}
+char const *
+ELFSymbolHelperMixin::getVisibilityStr(uint8_t type) {
+ switch (type) {
+ default: return "(UNKNOWN)";
+
+#define CASE(TYPE) \
+ case STV_##TYPE: return #TYPE;
+
+ CASE(DEFAULT)
+ CASE(INTERNAL)
+ CASE(HIDDEN)
+ CASE(PROTECTED)
+
+#undef CASE
+ }
+}
diff --git a/driver/linkloader/lib/ELFTypes.cpp b/driver/linkloader/lib/ELFTypes.cpp
new file mode 100644
index 0000000..7c82eab
--- /dev/null
+++ b/driver/linkloader/lib/ELFTypes.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ELFTypes.h"
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/Format.h>
+
+namespace detail {
+
+#define ELF_TYPE_PRINT_OPERATOR(TYPE, FORMAT_WIDTH) \
+ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, TYPE const &val) { \
+ os << llvm::format("%0*x", FORMAT_WIDTH, val.value); \
+ return os; \
+ }
+
+ ELF_TYPE_PRINT_OPERATOR(ELF32Address, 8)
+ ELF_TYPE_PRINT_OPERATOR(ELF32Offset, 8)
+ ELF_TYPE_PRINT_OPERATOR(ELF64Address, 16)
+ ELF_TYPE_PRINT_OPERATOR(ELF64Offset, 16)
+
+#undef ELF_TYPE_PRINT_OPERATOR
+
+} // end namespace detail
diff --git a/driver/linkloader/lib/GOT.cpp b/driver/linkloader/lib/GOT.cpp
new file mode 100644
index 0000000..3f523c5
--- /dev/null
+++ b/driver/linkloader/lib/GOT.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include "GOT.h"
+
+void *got_symbol_addresses[NUM_OF_GOT_ENTRY];
+int got_symbol_indexes[NUM_OF_GOT_ENTRY];
+size_t got_symbol_count = 0;
+
+void *got_address()
+{
+ return &got_symbol_addresses[0];
+}
+
+int search_got(int symbol_index, void *addr, uint8_t bind_type)
+{
+ size_t i;
+
+ // For local symbols (R_MIPS_GOT16), we only store the high 16-bit value
+ // after adding 0x8000.
+ if (bind_type == STB_LOCAL)
+ addr = (void *)(((intptr_t)addr + 0x8000) & 0xFFFF0000);
+
+ for (i = 0; i < got_symbol_count; i++) {
+ if (got_symbol_indexes[i] == symbol_index) {
+ if (bind_type == STB_LOCAL) {
+ // Check if the value is the same for local symbols.
+ // If yes, we can reuse this entry.
+ // If not, we continue searching.
+ if (got_symbol_addresses[i] == addr) {
+ return i;
+ }
+ }
+ else {
+ // The value must be the same for global symbols .
+ rsl_assert (got_symbol_addresses[i] == addr
+ && "MIPS GOT address error.");
+ return i;
+ }
+ }
+ }
+
+ // Cannot find this symbol with correct value, so we need to create one
+ rsl_assert (got_symbol_count < NUM_OF_GOT_ENTRY && "MIPS GOT is full.");
+ got_symbol_indexes[got_symbol_count] = symbol_index;
+ got_symbol_addresses[got_symbol_count] = addr;
+ got_symbol_count++;
+ return (got_symbol_count - 1);
+}
diff --git a/driver/linkloader/lib/MemChunk.cpp b/driver/linkloader/lib/MemChunk.cpp
new file mode 100644
index 0000000..24dcf8e
--- /dev/null
+++ b/driver/linkloader/lib/MemChunk.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MemChunk.h"
+
+#include "utils/flush_cpu_cache.h"
+#include "utils/helper.h"
+
+#include <llvm/Support/raw_ostream.h>
+
+#include <sys/mman.h>
+
+#include <stdlib.h>
+
+#ifndef MAP_32BIT
+#define MAP_32BIT 0
+// Note: If the <sys/mman.h> does not come with MAP_32BIT, then we
+// define it as zero, so that it won't manipulate the flags.
+#endif
+
+//#define USE_FIXED_ADDR_MEM_CHUNK 1
+
+#if USE_FIXED_ADDR_MEM_CHUNK
+static uintptr_t StartAddr = 0x7e000000UL;
+#endif
+
+MemChunk::MemChunk() : buf((unsigned char *)MAP_FAILED), buf_size(0) {
+}
+
+MemChunk::~MemChunk() {
+ if (buf != MAP_FAILED) {
+ munmap(buf, buf_size);
+ }
+}
+
+bool MemChunk::allocate(size_t size) {
+ if (size == 0) {
+ return true;
+ }
+#if USE_FIXED_ADDR_MEM_CHUNK
+ buf = (unsigned char *)mmap((void *)StartAddr, size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_32BIT,
+ -1, 0);
+#else
+ buf = (unsigned char *)mmap(0, size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_32BIT,
+ -1, 0);
+#endif
+
+ if (buf == MAP_FAILED) {
+ return false;
+ }
+
+#if USE_FIXED_ADDR_MEM_CHUNK
+ StartAddr += (size + 4095) / 4096 * 4096;
+#endif
+
+ buf_size = size;
+ return true;
+}
+
+void MemChunk::print() const {
+ if (buf != MAP_FAILED) {
+ dump_hex(buf, buf_size, 0, buf_size);
+ }
+}
+
+bool MemChunk::protect(int prot) {
+ if (buf_size > 0) {
+ int ret = mprotect((void *)buf, buf_size, prot);
+ if (ret == -1) {
+ llvm::errs() << "Error: Can't mprotect.\n";
+ return false;
+ }
+
+ if (prot & PROT_EXEC) {
+ FLUSH_CPU_CACHE(buf, buf + buf_size);
+ }
+ }
+
+ return true;
+}
diff --git a/driver/linkloader/lib/StubLayout.cpp b/driver/linkloader/lib/StubLayout.cpp
new file mode 100644
index 0000000..00555ad
--- /dev/null
+++ b/driver/linkloader/lib/StubLayout.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "StubLayout.h"
+
+#include "utils/flush_cpu_cache.h"
+#include "utils/raw_ostream.h"
+#include "utils/rsl_assert.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+StubLayout::StubLayout() : table(NULL), count(0) {
+}
+
+void StubLayout::initStubTable(unsigned char *table_, size_t count_) {
+ table = table_;
+ count = count_;
+}
+
+void *StubLayout::allocateStub(void *addr) {
+ // Check if we have created this stub or not.
+ std::map<void *, void *>::iterator index_iter = stub_index.find(addr);
+
+ if (index_iter != stub_index.end()) {
+ return index_iter->second;
+ }
+
+ // We have to create a new stub
+ if (count == 0) {
+ // No free stub slot is available
+ return NULL;
+ }
+
+ // Initialize the stub
+ unsigned char *stub = table;
+ setStubAddress(stub, addr);
+ stub_index.insert(std::make_pair(addr, stub));
+
+ // Increase the free stub slot pointer
+ table += getUnitStubSize();
+ count--;
+
+ return stub;
+}
+
+size_t StubLayout::calcStubTableSize(size_t count) const {
+ return count * getUnitStubSize();
+}
+
+size_t StubLayoutARM::getUnitStubSize() const {
+ return 8;
+}
+
+void StubLayoutARM::setStubAddress(void *stub_, void *addr) {
+ uint8_t *stub = (uint8_t *)stub_;
+ stub[0] = 0x04; // ldr pc, [pc, #-4]
+ stub[1] = 0xf0; // ldr pc, [pc, #-4]
+ stub[2] = 0x1f; // ldr pc, [pc, #-4]
+ stub[3] = 0xe5; // ldr pc, [pc, #-4]
+
+ void **target = (void **)(stub + 4);
+ *target = addr;
+}
+
+size_t StubLayoutMIPS::getUnitStubSize() const {
+ return 16;
+}
+
+void StubLayoutMIPS::setStubAddress(void *stub_, void *addr) {
+ uint32_t addr32 = (uint32_t)(uintptr_t)addr;
+ uint16_t addr_hi16 = (addr32 >> 16) & 0xffff;
+ uint16_t addr_lo16 = addr32 & 0xffff;
+
+ uint32_t *stub = (uint32_t *)stub_;
+ stub[0] = 0x3c190000ul | addr_hi16; // lui
+ stub[1] = 0x37390000ul | addr_lo16; // ori
+ stub[2] = 0x03200008ul; // jr (jump register)
+ stub[3] = 0x00000000ul; // nop
+}
diff --git a/driver/linkloader/main.cpp b/driver/linkloader/main.cpp
new file mode 100644
index 0000000..2ead7ec
--- /dev/null
+++ b/driver/linkloader/main.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ELFObject.h"
+
+#include "utils/serialize.h"
+#include "ELF.h"
+
+#include <llvm/ADT/OwningPtr.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <map>
+#include <stdio.h>
+#include <stdarg.h>
+
+using namespace std;
+
+bool open_mmap_file(char const *filename,
+ int &fd,
+ unsigned char const *&image,
+ size_t &size);
+
+void close_mmap_file(int fd,
+ unsigned char const *image,
+ size_t size);
+
+void dump_and_run_file(unsigned char const *image, size_t size,
+ int argc, char **argv);
+
+int main(int argc, char **argv) {
+ // Check arguments
+ if (argc < 2) {
+ llvm::errs() << "USAGE: " << argv[0] << " [ELFObjectFile] [ARGS]\n";
+ exit(EXIT_FAILURE);
+ }
+
+ // Filename from argument
+ char const *filename = argv[1];
+
+ // Open the file
+ int fd = -1;
+ unsigned char const *image = NULL;
+ size_t image_size = 0;
+
+ if (!open_mmap_file(filename, fd, image, image_size)) {
+ exit(EXIT_FAILURE);
+ }
+
+ // Dump and run the file
+ dump_and_run_file(image, image_size, argc - 1, argv + 1);
+
+ // Close the file
+ close_mmap_file(fd, image, image_size);
+
+ return EXIT_SUCCESS;
+}
+
+// FIXME: I don't like these stub as well. However, before we implement
+// x86 64bit far jump stub, we have to ensure find_sym only returns
+// near address.
+
+int stub_printf(char const *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int result = vprintf(fmt, ap);
+ va_end(ap);
+ return result;
+}
+
+int stub_scanf(char const *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int result = vscanf(fmt, ap);
+ va_end(ap);
+ return result;
+}
+
+void stub_srand(unsigned int seed) {
+ srand(seed);
+}
+
+int stub_rand() {
+ return rand();
+}
+
+time_t stub_time(time_t *output) {
+ return time(output);
+}
+
+void *find_sym(void *context, char const *name) {
+ struct func_entry_t {
+ char const *name;
+ size_t name_len;
+ void *addr;
+ };
+
+ static func_entry_t const tab[] = {
+#define DEF(NAME, ADDR) \
+ { NAME, sizeof(NAME) - 1, (void *)(ADDR) },
+
+ DEF("printf", stub_printf)
+ DEF("scanf", stub_scanf)
+ DEF("__isoc99_scanf", stub_scanf)
+ DEF("rand", stub_rand)
+ DEF("time", stub_time)
+ DEF("srand", stub_srand)
+#undef DEF
+ };
+
+ static size_t const tab_size = sizeof(tab) / sizeof(func_entry_t);
+
+ // Note: Since our table is small, we are using trivial O(n) searching
+ // function. For bigger table, it will be better to use binary
+ // search or hash function.
+ size_t name_len = strlen(name);
+ for (size_t i = 0; i < tab_size; ++i) {
+ if (name_len == tab[i].name_len && strcmp(name, tab[i].name) == 0) {
+ return tab[i].addr;
+ }
+ }
+
+ assert(0 && "Can't find symbol.");
+ return 0;
+}
+
+template <unsigned Bitwidth, typename Archiver>
+void dump_and_run_object(Archiver &AR, int argc, char **argv) {
+ llvm::OwningPtr<ELFObject<Bitwidth> > object(ELFObject<Bitwidth>::read(AR));
+
+ if (!object) {
+ llvm::errs() << "ERROR: Unable to load object\n";
+ }
+
+ object->print();
+ out().flush();
+
+ ELFSectionSymTab<Bitwidth> *symtab =
+ static_cast<ELFSectionSymTab<Bitwidth> *>(
+ object->getSectionByName(".symtab"));
+
+ object->relocate(find_sym, 0);
+ out() << "relocate finished!\n";
+ out().flush();
+
+ int machine = object->getHeader()->getMachine();
+
+ void *main_addr = symtab->getByName("main")->getAddress(machine);
+ out() << "main address: " << main_addr << "\n";
+ out().flush();
+
+ ((int (*)(int, char **))main_addr)(argc, argv);
+ fflush(stdout);
+}
+
+template <typename Archiver>
+void dump_and_run_file_from_archive(bool is32bit, Archiver &AR,
+ int argc, char **argv) {
+ if (is32bit) {
+ dump_and_run_object<32>(AR, argc, argv);
+ } else {
+ dump_and_run_object<64>(AR, argc, argv);
+ }
+}
+
+void dump_and_run_file(unsigned char const *image, size_t size,
+ int argc, char **argv) {
+ if (size < EI_NIDENT) {
+ llvm::errs() << "ERROR: ELF identification corrupted.\n";
+ return;
+ }
+
+ if (image[EI_DATA] != ELFDATA2LSB && image[EI_DATA] != ELFDATA2MSB) {
+ llvm::errs() << "ERROR: Unknown endianness.\n";
+ return;
+ }
+
+ if (image[EI_CLASS] != ELFCLASS32 && image[EI_CLASS] != ELFCLASS64) {
+ llvm::errs() << "ERROR: Unknown machine class.\n";
+ return;
+ }
+
+ bool isLittleEndian = (image[EI_DATA] == ELFDATA2LSB);
+ bool is32bit = (image[EI_CLASS] == ELFCLASS32);
+
+ if (isLittleEndian) {
+ ArchiveReaderLE AR(image, size);
+ dump_and_run_file_from_archive(is32bit, AR, argc, argv);
+ } else {
+ ArchiveReaderBE AR(image, size);
+ dump_and_run_file_from_archive(is32bit, AR, argc, argv);
+ }
+}
+
+bool open_mmap_file(char const *filename,
+ int &fd,
+ unsigned char const *&image,
+ size_t &size) {
+ // Query the file status
+ struct stat sb;
+ if (stat(filename, &sb) != 0) {
+ llvm::errs() << "ERROR: " << filename << " not found.\n";
+ return false;
+ }
+
+ if (!S_ISREG(sb.st_mode)) {
+ llvm::errs() << "ERROR: " << filename << " is not a regular file.\n";
+ return false;
+ }
+
+ size = (size_t)sb.st_size;
+
+ // Open the file in readonly mode
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ llvm::errs() << "ERROR: Unable to open " << filename << "\n";
+ return false;
+ }
+
+ // Map the file image
+ image = static_cast<unsigned char const *>(
+ mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0));
+
+ if (image == MAP_FAILED) {
+ llvm::errs() << "ERROR: Unable to map " << filename << " to memory.\n";
+ close(fd);
+ return false;
+ }
+
+ return true;
+}
+
+void close_mmap_file(int fd,
+ unsigned char const *image,
+ size_t size) {
+ if (image) {
+ munmap((void *)image, size);
+ }
+
+ if (fd >= 0) {
+ close(fd);
+ }
+}
diff --git a/driver/linkloader/tests/images/clean-testcases.sh b/driver/linkloader/tests/images/clean-testcases.sh
new file mode 100755
index 0000000..1c2d0be
--- /dev/null
+++ b/driver/linkloader/tests/images/clean-testcases.sh
@@ -0,0 +1,18 @@
+#!/bin/bash -e
+
+
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+rm -rf *.o *.bc
diff --git a/driver/linkloader/tests/images/gen-testcases.sh b/driver/linkloader/tests/images/gen-testcases.sh
new file mode 100755
index 0000000..26c7cdf
--- /dev/null
+++ b/driver/linkloader/tests/images/gen-testcases.sh
@@ -0,0 +1,41 @@
+#!/bin/bash -e
+
+
+# Copyright (C) 2011-2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+CYAN='\033[1;36m'
+RESET='\033[m'
+
+echo -e "${CYAN}Generating bitcode ...${RESET}"
+clang -emit-llvm -std=c89 -Wall -c test.c -o test.bc
+clang -emit-llvm -std=c89 -Wall -c simple-test.c -o simple-test.bc
+clang -emit-llvm -std=c89 -Wall -c rodata-test.c -o rodata-test.bc
+
+function gen_test_cases {
+ echo -e "${CYAN}Generating for $1 ...${RESET}"
+ llc -filetype=obj -relocation-model=static -mtriple $2 $3 test.bc -o test-$1.o
+ llc -filetype=obj -relocation-model=static -mtriple $2 $3 simple-test.bc -o simple-test-$1.o
+ llc -filetype=obj -relocation-model=static -mtriple $2 $3 rodata-test.bc -o rodata-test-$1.o
+}
+
+gen_test_cases arm armv7-none-linux-gnueabi
+gen_test_cases tegra2 armv7-none-linux-gnueabi '-mcpu=cortex-a9 -mattr=+vfp3'
+gen_test_cases thumb2 thumb-none-linux-gnueabi '-march=thumb -mattr=+thumb2'
+gen_test_cases thumb2lc thumb-none-linux-gnueabi '-mattr=+thumb2,+neonfp,+vfp3 -arm-long-calls'
+gen_test_cases thumb2lc-xoom thumb-none-linux-gnueabi '-mattr=+thumb2 -arm-long-calls'
+gen_test_cases x86_32 i686-none-linux
+gen_test_cases x86_64 x86_64-none-linux
+gen_test_cases mipsel mipsel-none-linux-gnueabi
diff --git a/driver/linkloader/tests/images/rodata-test.c b/driver/linkloader/tests/images/rodata-test.c
new file mode 100644
index 0000000..d695d01
--- /dev/null
+++ b/driver/linkloader/tests/images/rodata-test.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include<stdio.h>
+
+static char const *const test_str[] = {
+ "string 1",
+ "string 2",
+ "string 3",
+ "long long long long long long string"
+};
+
+static size_t test_str_count = sizeof(test_str) / sizeof(char const *const);
+
+int main(){
+ int i;
+ printf("test_str: %p\n", &test_str);
+ for (i = 0; i < test_str_count; ++i) {
+ printf("%p\n", test_str[i]);
+ printf("%s\n", test_str[i]);
+ }
+
+ return 0;
+}
diff --git a/driver/linkloader/tests/images/simple-test.c b/driver/linkloader/tests/images/simple-test.c
new file mode 100644
index 0000000..c59201d
--- /dev/null
+++ b/driver/linkloader/tests/images/simple-test.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+int main() {
+ srand(time(NULL));
+
+ unsigned int ans = rand() % 100;
+ unsigned int user = 100;
+ unsigned int left = 0;
+ unsigned int right = 99;
+
+ printf("Hello, droid! Let's play a number guessing game!\n");
+
+ while (user != ans) {
+ printf("Please input a number [%d-%d]:\n", left, right);
+
+ if (scanf("%u", &user) != 1) {
+ break;
+ }
+
+ if (user < left || user > right) {
+ /* Out of range, ignore this answer. */
+ continue;
+ } else if (user == ans) {
+ printf("You got it!\n");
+ break;
+ } else if (user < ans) {
+ left = user;
+ } else {
+ right = user;
+ }
+ }
+
+ return 0;
+}
diff --git a/driver/linkloader/tests/images/test.c b/driver/linkloader/tests/images/test.c
new file mode 100644
index 0000000..01b69a1
--- /dev/null
+++ b/driver/linkloader/tests/images/test.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include<stdio.h>
+static void hello_function(const char *ptr){
+ printf("%s", ptr);
+}
+int my_add(int para_x, int para_y){
+ return para_x + para_y;
+}
+int global_z_i;
+double global_z_d;
+int global_big_z_i[1000];
+double global_big_z_d[1000];
+static int global_static_z_i;
+static double global_static_z_d;
+static int global_static_big_z_i[1000];
+static double global_static_big_z_d[1000];
+int global_z_i_init = 1;
+double global_z_d_init = 1.1;
+/*extern int extern_z_i; */
+/*extern double extern_z_d;*/
+int main(){
+ static int local_static_z_i;
+ static double local_static_z_d;
+ static int local_static_z_i_init = 2;
+ static double local_static_z_d_init = 2.2;
+ local_static_z_i = local_static_z_i_init;
+ local_static_z_d = local_static_z_d_init;
+ printf("%d %f\n", local_static_z_i, local_static_z_d);
+ printf("%d %f\n", local_static_z_i_init, local_static_z_d_init);
+ hello_function("Hello world!1\n");
+ hello_function("Hello world!2\n");
+ hello_function("Hello world!3\n");
+ global_z_i = my_add(1,2);
+ global_z_d = 3.3;
+ printf("%d %f\n", global_z_i, global_z_d);
+ global_big_z_i[100] = 4;
+ global_big_z_d[100] = 4.4;
+ printf("%d %f\n", global_big_z_i[100], global_big_z_d[100]);
+ global_static_z_i = my_add(2,1);
+ global_static_z_d = 3.3;
+ printf("%d %f\n", global_static_z_i, global_static_z_d);
+ int local_z_i = global_static_z_i = global_z_i;
+ double local_z_d = global_static_z_d = global_z_d;
+ printf("%d %f\n", local_z_i, local_z_d);
+ global_static_big_z_i[500] = 5;
+ global_static_big_z_d[500] = 5.5;
+ printf("%d %f\n", global_static_big_z_i[500], global_static_big_z_d[500]);
+ global_z_i_init = 6;
+ global_z_d_init = 6.6;
+ printf("%d %f\n", global_z_i_init, global_z_d_init);
+ /*printf("%d %f\n", extern_z_i, extern_z_d);*/
+ return 0;
+}
diff --git a/driver/linkloader/tests/stubs/arm-stub.c b/driver/linkloader/tests/stubs/arm-stub.c
new file mode 100644
index 0000000..2138f9a
--- /dev/null
+++ b/driver/linkloader/tests/stubs/arm-stub.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+
+// Note: The first instruction stands for ldr, which loads the data from
+// memory to the specified register. Notice that due to the pipeline design,
+// when ldr is executed, the program will be advanced by 8. So, to get our
+// address we should substract it by 4.
+
+uint32_t stub[] = {
+ 0xe51ff004ul, // ldr pc, [pc, #-4]
+ 0x00000000ul // address
+};
+
+int test() {
+ printf("hello world!\n");
+ return 5;
+}
+
+int main() {
+ int (*f)() = (int (*)())stub;
+ stub[1] = (uint32_t)(uintptr_t)test;
+
+ printf("return = %d\n", f());
+ return EXIT_SUCCESS;
+}
diff --git a/driver/linkloader/tests/stubs/mips-stub.c b/driver/linkloader/tests/stubs/mips-stub.c
new file mode 100644
index 0000000..ff34d03
--- /dev/null
+++ b/driver/linkloader/tests/stubs/mips-stub.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+// --------------
+// Register Usage
+// --------------
+// $0 zero
+// $1 at
+// $2-$3 function return value registers
+// $4-$7 function argument registers
+// $8-$15 temporary
+// $16-$23 saved register
+// $24-$25 temporary
+// $26-$27 os kernel
+// $28 global pointer
+// $29 stack pointer
+// $30 saved register
+// $31 return addres reigster
+
+// --------------------
+// Instruction Encoding
+// --------------------
+// lui: 0011 1100 000t tttt iiii iiii iiii iiii
+// ori: 0011 01ss ssst tttt iiii iiii iiii iiii
+// jr: 0000 00ss sss0 0000 0000 0000 0000 1000
+// nop: 0000 0000 0000 0000 0000 0000 0000 0000
+
+uint32_t stub[] = {
+ 0x3c190000ul,
+ 0x37390000ul,
+ 0x03200008ul,
+ 0x00000000ul
+};
+
+int test() {
+ printf("hello world!\n");
+ return 5;
+}
+
+int main() {
+ int (*f)() = (int (*)())stub;
+ stub[0] |= (((uint32_t)(uintptr_t)test) >> 16) & 0xffff;
+ stub[1] |= (((uint32_t)(uintptr_t)test)) & 0xffff;
+
+ printf("return = %d\n", f());
+ return EXIT_SUCCESS;
+}
diff --git a/driver/linkloader/tests/stubs/stub-layout-test.cpp b/driver/linkloader/tests/stubs/stub-layout-test.cpp
new file mode 100644
index 0000000..ba07cd2
--- /dev/null
+++ b/driver/linkloader/tests/stubs/stub-layout-test.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "StubLayout.h"
+
+void function1() {
+ printf("hello ");
+}
+
+void function2() {
+ printf("world!\n");
+}
+
+int main() {
+ StubLayout stubs;
+
+ void (*func1)() = (void (*)())stubs.allocateStub((void *)&function1);
+ void (*func2)() = (void (*)())stubs.allocateStub((void *)&function2);
+
+ if (!func1) {
+ fprintf(stderr, "ERROR: Unable to allocate stub for function1\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (!func2) {
+ fprintf(stderr, "ERROR: Unable to allocate stub for function2\n");
+ exit(EXIT_FAILURE);
+ }
+
+ function1();
+ function2();
+
+ func1();
+ func2();
+
+ return EXIT_SUCCESS;
+}
diff --git a/driver/linkloader/utils/flush_cpu_cache.h b/driver/linkloader/utils/flush_cpu_cache.h
new file mode 100644
index 0000000..7a269ed
--- /dev/null
+++ b/driver/linkloader/utils/flush_cpu_cache.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLUSH_CPU_CACHE_H
+#define FLUSH_CPU_CACHE_H
+
+#if defined(__arm__) || defined(__mips__)
+
+// Note: Though we wish to use the gcc builtin function __clear_cache to
+// invalidate the instruction cache; however, the toolchain of Android
+// has not supported it properly. We are going to use cacheflush system
+// call to invalidate the instruction cache.
+//
+// As a side note, Dalvik VM use the same system call to invalidate the
+// instruction as well.
+
+#include <unistd.h>
+
+#define FLUSH_CPU_CACHE(BEGIN, END) \
+ cacheflush(((long)(BEGIN)), ((long)(END)), 0)
+
+#if 0 && defined(__mips__)
+
+// Note: Following code does not work with Android Toolchain, though they
+// works while using standalone mips-linux-gnu-gcc.
+
+#include <sys/cachectl.h>
+#define FLUSH_CPU_CACHE(BEGIN, END) \
+ _flush_cache(reinterpret_cast<char*>(BEGIN), END-BEGIN+1, BCACHE);
+
+#endif
+
+#else
+
+#define FLUSH_CPU_CACHE(BEGIN, END) do { } while (0)
+
+#endif
+
+#endif // FLUSH_CPU_CACHE_H
diff --git a/driver/linkloader/utils/helper.cpp b/driver/linkloader/utils/helper.cpp
new file mode 100644
index 0000000..2dce54f
--- /dev/null
+++ b/driver/linkloader/utils/helper.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "helper.h"
+#include "raw_ostream.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+
+using namespace llvm;
+
+void dump_hex(unsigned char const *data,
+ size_t size, size_t begin, size_t end) {
+ if (end <= begin) {
+ // Nothing to print now. Return directly.
+ return;
+ }
+
+ size_t lower = begin & (~0xfUL);
+ size_t upper = (end & (~0xfUL)) ? end : ((end + 16UL) & (~0xfUL));
+
+ for (size_t i = lower; i < upper; i += 16) {
+ out() << format("%08x", i) << ':';
+
+ if (i < begin) {
+ out().changeColor(raw_ostream::MAGENTA);
+ }
+
+ for (size_t j = i, k = i + 16; j < k; ++j) {
+ if (j == begin) {
+ out().resetColor();
+ }
+
+ if (j == end) {
+ out().changeColor(raw_ostream::MAGENTA);
+ }
+
+ if (j < size) {
+ out() << ' ' << format("%02x", (unsigned)data[j]);
+ }
+ }
+
+ out().resetColor();
+ out() << " ";
+
+ for (size_t j = i, k = i + 16; j < k; ++j) {
+ if (data[j] > 0x20 && data[j] < 0x7f) {
+ out() << (char)data[j];
+ } else {
+ out() << '.';
+ }
+ }
+
+ out() << '\n';
+ }
+}
diff --git a/driver/linkloader/utils/helper.h b/driver/linkloader/utils/helper.h
new file mode 100644
index 0000000..000666a
--- /dev/null
+++ b/driver/linkloader/utils/helper.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HELPER_H
+#define HELPER_H
+
+#include <stdlib.h>
+
+extern void dump_hex(unsigned char const *data,
+ size_t size, size_t begin, size_t end);
+
+#endif // HELPER_H
diff --git a/driver/linkloader/utils/raw_ostream.cpp b/driver/linkloader/utils/raw_ostream.cpp
new file mode 100644
index 0000000..7efd10e
--- /dev/null
+++ b/driver/linkloader/utils/raw_ostream.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "raw_ostream.h"
+
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/Format.h>
+#include <cstdarg>
+#include <cstring>
+
+llvm::raw_ostream &out() {
+ static llvm::raw_ostream &singleton = llvm::outs();
+ return singleton;
+}
+
+MyFormat const fillformat(char const fill_char, // Fill character.
+ int const length, // Fill Width.
+ char const *format_s, // Format string.
+ ...) { // Format variable.
+ using namespace std;
+ struct MyFormat t_format;
+ va_list valist;
+ va_start(valist, format_s);
+ t_format.ptr = new char[length+1];
+ t_format.ptr[length] = '\0';
+ vsnprintf(t_format.ptr, length, format_s, valist);
+ int real_len = strlen(t_format.ptr);
+ int fill_len = length;
+ memmove(t_format.ptr + fill_len, t_format.ptr, real_len);
+ memset(t_format.ptr, fill_char, fill_len);
+ return t_format;
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &os, MyFormat const &mf) {
+ os << mf.ptr;
+ delete mf.ptr;
+ return os;
+}
diff --git a/driver/linkloader/utils/raw_ostream.h b/driver/linkloader/utils/raw_ostream.h
new file mode 100644
index 0000000..0f7a5be
--- /dev/null
+++ b/driver/linkloader/utils/raw_ostream.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RAW_OSTREAM_H
+#define RAW_OSTREAM_H
+
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/Format.h>
+
+extern llvm::raw_ostream &out();
+struct MyFormat {
+ char *ptr;
+};
+extern MyFormat const fillformat(char const, // Fill character.
+ int const, // Fill Width.
+ char const * = "", // Format string.
+ ...); // Format variable.
+extern llvm::raw_ostream &operator<<(llvm::raw_ostream &, MyFormat const &);
+
+#endif // RAW_OSTREAM_H
diff --git a/driver/linkloader/utils/rsl_assert.cpp b/driver/linkloader/utils/rsl_assert.cpp
new file mode 100644
index 0000000..cdd3207
--- /dev/null
+++ b/driver/linkloader/utils/rsl_assert.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rsl_assert.h"
+
+#include <llvm/Support/raw_ostream.h>
+
+#include <stdlib.h>
+
+#if !defined(__HOST__)
+#define LOG_TAG "bcc"
+#include <cutils/log.h>
+#endif
+
+extern "C" void ASSERT_FAILED(char const *file,
+ unsigned line,
+ char const *expr) {
+#if defined(__HOST__)
+ llvm::errs() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
+ llvm::errs() << "rslAssert [" << file << ":" << line << "] " << expr << "\n";
+ llvm::errs() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
+#else
+ ALOGE("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ ALOGE("rslAssert [%s:%d] %s\n", file, line, expr);
+ ALOGE("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+#endif
+
+ abort();
+}
diff --git a/driver/linkloader/utils/rsl_assert.h b/driver/linkloader/utils/rsl_assert.h
new file mode 100644
index 0000000..cd20b83
--- /dev/null
+++ b/driver/linkloader/utils/rsl_assert.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RSL_ASSERT_H
+#define RSL_ASSERT_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern void ASSERT_FAILED(char const *file,
+ unsigned line,
+ char const *expr);
+
+#if defined(__cplusplus)
+} // extern "C"
+#endif
+
+#ifdef RSL_NDEBUG
+
+#define rsl_assert(EXPR) \
+ do { } while (0)
+
+#else
+
+#define rsl_assert(EXPR) \
+ do { \
+ if (!(EXPR)) { \
+ ASSERT_FAILED(__FILE__, __LINE__, #EXPR); \
+ } \
+ } while (0)
+
+#endif
+
+#endif // RSL_ASSERT_H
diff --git a/driver/linkloader/utils/serialize.h b/driver/linkloader/utils/serialize.h
new file mode 100644
index 0000000..3d15158
--- /dev/null
+++ b/driver/linkloader/utils/serialize.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !defined(SERIALIZE_H)
+#define SERIALIZE_H
+
+#include "traits.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "utils/rsl_assert.h"
+#include <string.h>
+#include <stdint.h>
+#include <stddef.h>
+
+namespace detail {
+ inline bool is_host_little_endian() {
+ unsigned long one = 0x1UL;
+ return *reinterpret_cast<unsigned char *>(&one);
+ }
+
+ inline void swap_byte_order(unsigned char (&array)[1]) {
+ // Nothing to do
+ }
+
+ inline void swap_byte_order(unsigned char (&array)[2]) {
+ std::swap(array[0], array[1]);
+ }
+
+ inline void swap_byte_order(unsigned char (&array)[4]) {
+ std::swap(array[0], array[3]);
+ std::swap(array[1], array[2]);
+ }
+
+ inline void swap_byte_order(unsigned char (&array)[8]) {
+ std::swap(array[0], array[7]);
+ std::swap(array[1], array[6]);
+ std::swap(array[2], array[5]);
+ std::swap(array[3], array[4]);
+ }
+}
+
+
+template <bool isArchiveLittleEndian>
+class ArchiveReader {
+private:
+ unsigned char const *buf_begin;
+ unsigned char const *buf_end;
+ unsigned char const *cursor;
+ unsigned char const *cursor_base;
+
+ bool good;
+
+public:
+ ArchiveReader(unsigned char const *buf = NULL, size_t size = 0)
+ : buf_begin(buf), buf_end(buf + size),
+ cursor(buf), cursor_base(NULL), good(buf != NULL) {
+ }
+
+ void prologue(size_t size) {
+ rsl_assert(cursor_base == NULL);
+ cursor_base = cursor;
+ }
+
+ void epilogue(size_t size) {
+ rsl_assert(cursor_base != NULL);
+ rsl_assert(cursor_base + size >= cursor);
+ cursor = cursor_base + size;
+ cursor_base = NULL;
+ }
+
+ void seek(off_t off, bool from_begin = false) {
+ if (from_begin) {
+ cursor = buf_begin + off;
+ } else {
+ cursor += off;
+ }
+ }
+
+ void readBytes(void *array, size_t size) {
+ if (!good || cursor + size > buf_end) {
+ good = false;
+ } else {
+ memcpy(array, cursor, size);
+ }
+ }
+
+ template <size_t size>
+ void operator&(char (&array)[size]) {
+ readBytes(array, size);
+ seek(size);
+ }
+
+ template <size_t size>
+ void operator&(unsigned char (&array)[size]) {
+ readBytes(array, size);
+ seek(size);
+ }
+
+ template <typename T>
+ void operator&(T &v) {
+ seekAlignment<T>();
+ readBytes(&v, TypeTraits<T>::size);
+ seek(TypeTraits<T>::size);
+
+ if (isArchiveLittleEndian != detail::is_host_little_endian()) {
+ detail::swap_byte_order(
+ reinterpret_cast<unsigned char (&)[TypeTraits<T>::size]>(v));
+ }
+ }
+
+ operator void const *() const {
+ return good ? this : 0;
+ }
+
+ bool operator!() const {
+ return !good;
+ }
+
+private:
+ template <typename T>
+ void seekAlignment() {
+ size_t align = TypeTraits<T>::align;
+ size_t delta = static_cast<size_t>(cursor - buf_begin) % align;
+
+ if (delta > 0) {
+ seek(align - delta);
+ }
+ }
+
+};
+
+typedef ArchiveReader<true> ArchiveReaderLE;
+typedef ArchiveReader<false> ArchiveReaderBE;
+
+#endif // SERIALIZE_H
diff --git a/driver/linkloader/utils/traits.h b/driver/linkloader/utils/traits.h
new file mode 100644
index 0000000..df7e7f7
--- /dev/null
+++ b/driver/linkloader/utils/traits.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TRAITS_H
+#define TRAITS_H
+
+#include <stddef.h>
+
+template <typename Type>
+struct TypeTraits {
+private:
+ struct AlignmentTest {
+ char pending;
+ Type element;
+ };
+
+public:
+ enum { size = sizeof(Type) };
+ enum { align = offsetof(AlignmentTest, element) };
+};
+
+#define TYPE_TRAITS_SPECIALIZE(TYPE, SIZE, ALIGN) \
+template <> \
+struct TypeTraits<TYPE> { \
+ enum { size = SIZE }; \
+ enum { align = ALIGN }; \
+};
+
+#endif // TRAITS_H