Usermode/ld-acess - Fix dynamic linking quirk (STB_WEAK and R_COPY)
[tpg/acess2.git] / Usermode / Libraries / ld-acess.so_src / elf.c
index 236983c..e3109b4 100644 (file)
@@ -4,8 +4,10 @@
  *
  * elf.c
  * - ELF32/ELF64 relocation
+ *
+ * TODO: Have GetSymbol() return a symbol "strength" on success. Allows STB_WEAK to be overriden by STB_GLOBAL
  */
-#ifndef DEBUG  // This code is #include'd from the kernel, so DEBUG may already be defined
+#ifndef KERNEL_VERSION
 # define DEBUG 0
 #endif
 
@@ -29,7 +31,8 @@
 
 #define WARNING(f,...) SysDebug("WARN: "f ,## __VA_ARGS__)     // Malformed file
 #define NOTICE(f,...)  SysDebug("NOTICE: "f ,## __VA_ARGS__)   // Missing relocation
-#define TRACE(f,...)   DEBUG_OUT("TRACE:%s:%i "f, __func__, __LINE__ ,## __VA_ARGS__)  // Debugging trace
+//#define TRACE(f,...) DEBUG_OUT("TRACE:%s:%i "f, __func__, __LINE__ ,## __VA_ARGS__)  // Debugging trace
+#define TRACE(f,...)   DEBUG_OUT("TRACE:%s "f, __func__,## __VA_ARGS__)        // Debugging trace
 
 #ifndef DISABLE_ELF64
 # define SUPPORT_ELF64
@@ -151,12 +154,23 @@ int elf_doRelocate_386(tElfRelocInfo *Info, uint32_t r_info, uint32_t *ptr, Elf3
        case R_386_COPY: {
                void *old_symval = symval;
                GetSymbol(Info->strtab + sym->st_name, &symval, &size, Info->Base);
-               if( symval == old_symval ) {
-                       WARNING("Can't find required external symbol '%s'", Info->strtab + sym->st_name);
-                       return 1;
+               if( symval == old_symval )
+               {
+                       if( ELF32_ST_BIND(sym->st_info) != STB_WEAK )
+                       {
+                               WARNING("sym={val:%p,size:0x%x,info:0x%x,other:0x%x,shndx:%i}",
+                                       sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx);
+                               WARNING("Can't find required external symbol '%s' for R_386_COPY", Info->strtab + sym->st_name);
+                               return 1;
+                       }
+                       // Don't bother doing the memcpy
+                       TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size);
+               }
+               else
+               {
+                       TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size);
+                       memcpy(ptr, symval, size);
                }
-               TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size);
-               memcpy(ptr, symval, size);
                break; }
 
        default:
@@ -223,7 +237,6 @@ void *Elf32Relocate(void *Base, char **envp, const char *Filename)
        const Elf32_Ehdr        *hdr = Base;
        char    *libPath;
        intptr_t        iRealBase = -1;
-       intptr_t        iBaseDiff;
        Elf32_Rel       *rel = NULL;
        Elf32_Rela      *rela = NULL;
        void    *plt = NULL;
@@ -264,10 +277,11 @@ void *Elf32Relocate(void *Base, char **envp, const char *Filename)
        
        // Page Align real base
        iRealBase &= ~0xFFF;
-       TRACE("True Base = 0x%x, Compiled Base = 0x%x", Base, iRealBase);
        
        // Adjust "Real" Base
-       iBaseDiff = (intptr_t)Base - iRealBase;
+       const intptr_t  iBaseDiff = (intptr_t)Base - iRealBase;
+
+       TRACE("True Base = 0x%x, Compiled Base = 0x%x, Difference = 0x%x", Base, iRealBase, iBaseDiff);
 
        // Check if a PT_DYNAMIC segement was found
        if(!dynamicTab) {
@@ -342,15 +356,25 @@ void *Elf32Relocate(void *Base, char **envp, const char *Filename)
                }
                else
                {
-                       // TODO: What about weak locally-defined symbols?
-                       if( ELF32_ST_BIND(sym->st_info) == STB_WEAK )
+                       void *newval;
+                       size_t  newsize;
+                       if( ELF32_ST_BIND(sym->st_info) != STB_WEAK )
                        {
-                               WARNING("TODO: Weak bound local symbols '%s'", name);
-                               assert(ELF32_ST_BIND(sym->st_info) != STB_WEAK);
-                               return NULL;
+                               TRACE("Sym %i'%s' = %p (local)", i, name, sym->st_value + iBaseDiff);
+                               sym->st_value += iBaseDiff;
+                       }
+                       // If GetSymbol doesn't return a strong/global symbol value
+                       else if( GetSymbol(name, &newval, &newsize, Base) != 1 )
+                       {
+                               TRACE("Sym %i'%s' = %p (Local weak)", i, name, sym->st_value + iBaseDiff);
+                               sym->st_value += iBaseDiff;
+                       }
+                       else
+                       {
+                               TRACE("Sym %i'%s' = %p+0x%x (Extern weak)", i, name, newval, newsize);
+                               sym->st_value = (uintptr_t)newval;
+                               sym->st_size = newsize;
                        }
-                       TRACE("Sym %i'%s' %p += 0x%x", i, name, sym->st_value, iBaseDiff);
-                       sym->st_value += iBaseDiff;
                }
        }
 
@@ -445,7 +469,7 @@ void *Elf32Relocate(void *Base, char **envp, const char *Filename)
                {
                        // Handled previously
                        // TODO: What about weak locally-defined symbols?
-                       assert( ELF32_ST_BIND(sym->st_info) != STB_WEAK );
+                       //assert( ELF32_ST_BIND(sym->st_info) != STB_WEAK );
                }
        }
        if( fail ) {
@@ -670,14 +694,18 @@ int Elf32GetSymbolInfo(void *Base, const char *Name, void **Addr, size_t *Size,
 
 int Elf32GetSymbol(void *Base, const char *Name, void **ret, size_t *Size)
 {
-        int    section;
+        int    section, binding;
        TRACE("Elf32GetSymbol(%p,%s,...)", Base, Name);
-       if( Elf32GetSymbolInfo(Base, Name, ret, Size, &section, NULL, NULL) )
+       if( Elf32GetSymbolInfo(Base, Name, ret, Size, &section, &binding, NULL) )
                return 0;
        if( section == SHN_UNDEF ) {
-               TRACE("Elf32GetSymbol: Undefined", *ret, (Size?*Size:0), section);
+               TRACE("Elf32GetSymbol: Undefined %p", *ret, (Size?*Size:0), section);
                return 0;
        }
+       if( binding == STB_WEAK ) {
+               TRACE("Elf32GetSymbol: Weak, return %p+0x%x,section=%i", *ret, (Size?*Size:0), section);
+               return 2;
+       }
        TRACE("Elf32GetSymbol: Found %p+0x%x,section=%i", *ret, (Size?*Size:0), section);
        return 1;
 }

UCC git Repository :: git.ucc.asn.au