Merge "Fix DLEXT_WRITE_RELRO when loading multiple libs." am: 865866ee2b am: c950489599
am: ce62c05753

Change-Id: I234ee6e837fe2609918cee82121aa3994afbd4d8
diff --git a/linker/linker.cpp b/linker/linker.cpp
index c60ab6a..306b800 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -3987,7 +3987,7 @@
   /* Handle serializing/sharing the RELRO segment */
   if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
     if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
-                                       extinfo->relro_fd) < 0) {
+                                       extinfo->relro_fd, relro_fd_offset) < 0) {
       DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
              get_realpath(), strerror(errno));
       return false;
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 1aaa17f..3534287 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -831,16 +831,17 @@
  *   phdr_count  -> number of entries in tables
  *   load_bias   -> load bias
  *   fd          -> writable file descriptor to use
+ *   file_offset -> pointer to offset into file descriptor to use/update
  * Return:
  *   0 on error, -1 on failure (error code in errno).
  */
 int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table,
                                    size_t phdr_count,
                                    ElfW(Addr) load_bias,
-                                   int fd) {
+                                   int fd,
+                                   size_t* file_offset) {
   const ElfW(Phdr)* phdr = phdr_table;
   const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
-  ssize_t file_offset = 0;
 
   for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
     if (phdr->p_type != PT_GNU_RELRO) {
@@ -856,11 +857,11 @@
       return -1;
     }
     void* map = mmap(reinterpret_cast<void*>(seg_page_start), size, PROT_READ,
-                     MAP_PRIVATE|MAP_FIXED, fd, file_offset);
+                     MAP_PRIVATE|MAP_FIXED, fd, *file_offset);
     if (map == MAP_FAILED) {
       return -1;
     }
-    file_offset += size;
+    *file_offset += size;
   }
   return 0;
 }
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 9761bc8..5d1cfc2 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -119,7 +119,7 @@
                                  ElfW(Addr) load_bias);
 
 int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
-                                   ElfW(Addr) load_bias, int fd);
+                                   ElfW(Addr) load_bias, int fd, size_t* file_offset);
 
 int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
                              ElfW(Addr) load_bias, int fd, size_t* file_offset);
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 1bc5030..3af52d4 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -450,7 +450,21 @@
         fprintf(stderr, "in child: %s\n", dlerror());
         exit(1);
       }
-      exit(0);
+      fn f = reinterpret_cast<fn>(dlsym(handle, "getRandomNumber"));
+      ASSERT_DL_NOTNULL(f);
+      EXPECT_EQ(4, f());
+
+      if (recursive) {
+        fn f = reinterpret_cast<fn>(dlsym(handle, "getBiggerRandomNumber"));
+        ASSERT_DL_NOTNULL(f);
+        EXPECT_EQ(8, f());
+      }
+
+      uint32_t* taxicab_number =
+              reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
+      ASSERT_DL_NOTNULL(taxicab_number);
+      EXPECT_EQ(1729U, *taxicab_number);
+      exit(testing::Test::HasFailure());
     }
 
     // continuing in parent