OSDN Git Service

Add flag that makes linker honor min(p_vaddr)
authorDmitriy Ivanov <dimitry@google.com>
Sat, 6 Jun 2015 05:16:23 +0000 (22:16 -0700)
committerDmitriy Ivanov <dimitry@google.com>
Tue, 9 Jun 2015 20:44:31 +0000 (13:44 -0700)
Bug: http://b/21523078
Change-Id: Ice72766fb6ad3bd333c32b496e7870121e17a763

libc/include/android/dlext.h
linker/linker_phdr.cpp

index f10a8a2..40f610f 100644 (file)
@@ -73,6 +73,13 @@ enum {
    */
   ANDROID_DLEXT_FORCE_LOAD = 0x40,
 
+  /* When set, if the minimum p_vaddr of the ELF file's PT_LOAD segments is non-zero,
+   * the dynamic linker will load it at that address.
+   *
+   * This flag is for ART internal use only.
+   */
+  ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80,
+
   /* Mask of valid bits */
   ANDROID_DLEXT_VALID_FLAG_BITS       = ANDROID_DLEXT_RESERVED_ADDRESS |
                                         ANDROID_DLEXT_RESERVED_ADDRESS_HINT |
@@ -80,7 +87,8 @@ enum {
                                         ANDROID_DLEXT_USE_RELRO |
                                         ANDROID_DLEXT_USE_LIBRARY_FD |
                                         ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
-                                        ANDROID_DLEXT_FORCE_LOAD,
+                                        ANDROID_DLEXT_FORCE_LOAD |
+                                        ANDROID_DLEXT_FORCE_FIXED_VADDR,
 };
 
 typedef struct {
index 638c9d6..f586b08 100644 (file)
@@ -316,6 +316,8 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
   void* start;
   size_t reserved_size = 0;
   bool reserved_hint = true;
+  // Assume position independent executable by default.
+  uint8_t* mmap_hint = nullptr;
 
   if (extinfo != nullptr) {
     if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
@@ -324,6 +326,10 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
     } else if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS_HINT) {
       reserved_size = extinfo->reserved_size;
     }
+
+    if ((extinfo->flags & ANDROID_DLEXT_FORCE_FIXED_VADDR) != 0) {
+      mmap_hint = addr;
+    }
   }
 
   if (load_size_ > reserved_size) {
@@ -333,7 +339,7 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
       return false;
     }
     int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
-    start = mmap(nullptr, load_size_, PROT_NONE, mmap_flags, -1, 0);
+    start = mmap(mmap_hint, load_size_, PROT_NONE, mmap_flags, -1, 0);
     if (start == MAP_FAILED) {
       DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_);
       return false;