merge in mnc-release history after reset to mnc-dev
diff --git a/linker/linker.cpp b/linker/linker.cpp
index e84036a..b860f70 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1921,9 +1921,32 @@
             DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
             return false;
         }
-      } else {
-        // We got a definition.
+      } else { // We got a definition.
+#if !defined(__LP64__)
+        // When relocating dso with text_relocation .text segment is
+        // not executable. We need to restore elf flags before resolving
+        // STT_GNU_IFUNC symbol.
+        bool protect_segments = has_text_relocations &&
+                                lsi == this &&
+                                ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
+        if (protect_segments) {
+          if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
+            DL_ERR("can't protect segments for \"%s\": %s",
+                   get_realpath(), strerror(errno));
+            return false;
+          }
+        }
+#endif
         sym_addr = lsi->resolve_symbol_address(s);
+#if !defined(__LP64__)
+        if (protect_segments) {
+          if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
+            DL_ERR("can't unprotect loadable segments for \"%s\": %s",
+                   get_realpath(), strerror(errno));
+            return false;
+          }
+        }
+#endif
       }
       count_relocation(kRelocSymbol);
     }
@@ -1960,7 +1983,32 @@
         TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
                     reinterpret_cast<void*>(reloc),
                     reinterpret_cast<void*>(load_bias + addend));
-        *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(load_bias + addend);
+        {
+#if !defined(__LP64__)
+          // When relocating dso with text_relocation .text segment is
+          // not executable. We need to restore elf flags for this
+          // particular call.
+          if (has_text_relocations) {
+            if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
+              DL_ERR("can't protect segments for \"%s\": %s",
+                     get_realpath(), strerror(errno));
+              return false;
+            }
+          }
+#endif
+          ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
+#if !defined(__LP64__)
+          // Unprotect it afterwards...
+          if (has_text_relocations) {
+            if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
+              DL_ERR("can't unprotect loadable segments for \"%s\": %s",
+                     get_realpath(), strerror(errno));
+              return false;
+            }
+          }
+#endif
+          *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
+        }
         break;
 
 #if defined(__aarch64__)