Fix protected symbol lookups for mips

Bug: http://b/20694161
Change-Id: I5cc58034f9776e1db9cddc34abe48ef85f6048f4
(cherry picked from commit dbe26fdcc7de503539837467299b96c4a93084cc)
diff --git a/libc/include/elf.h b/libc/include/elf.h
index df768ba..dcf01ab 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -187,6 +187,11 @@
 #define STT_LOPROC    13
 #define STT_HIPROC    15
 
+#define STV_DEFAULT   0
+#define STV_INTERNAL  1
+#define STV_HIDDEN    2
+#define STV_PROTECTED 3
+
 /* The kernel uses NT_PRFPREG but glibc also offers NT_FPREGSET */
 #define NT_FPREGSET NT_PRFPREG
 
diff --git a/linker/linker_mips.cpp b/linker/linker_mips.cpp
index 7436180..a7a4bc0 100644
--- a/linker/linker_mips.cpp
+++ b/linker/linker_mips.cpp
@@ -157,20 +157,34 @@
     soinfo* lsi = nullptr;
     const ElfW(Sym)* s = nullptr;
 
-    const version_info* vi = nullptr;
+    ElfW(Word) st_visibility = (local_sym->st_other & 0x3);
 
-    if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
-      return false;
-    }
+    if (st_visibility == STV_DEFAULT) {
+      const version_info* vi = nullptr;
 
-    if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
+      if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
+        return false;
+      }
+
+      if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
+        return false;
+      }
+    } else if (st_visibility == STV_PROTECTED) {
+      if (local_sym->st_value == 0) {
+        DL_ERR("%s: invalid symbol \"%s\" (PROTECTED/UNDEFINED) ", get_soname(), sym_name);
+        return false;
+      }
+      s = local_sym;
+      lsi = this;
+    } else {
+      DL_ERR("%s: invalid symbol \"%s\" visibility: 0x%x", get_soname(), sym_name, st_visibility);
       return false;
     }
 
     if (s == nullptr) {
       // We only allow an undefined symbol if this is a weak reference.
       if (ELF_ST_BIND(local_sym->st_info) != STB_WEAK) {
-        DL_ERR("cannot locate \"%s\"...", sym_name);
+        DL_ERR("%s: cannot locate \"%s\"...", get_soname(), sym_name);
         return false;
       }
       *got = 0;