Sfoglia il codice sorgente

* ELF linker: improved dynamic symbol handling.
+ Read .gnu.version sections and ignore local symbols and symbols with non-current version.
+ Check that external symbols are actually present in dynamic objects.

git-svn-id: trunk@22832 -

sergei 12 anni fa
parent
commit
6023f73e2a
1 ha cambiato i file con 139 aggiunte e 18 eliminazioni
  1. 139 18
      compiler/ogelf.pas

+ 139 - 18
compiler/ogelf.pas

@@ -125,6 +125,8 @@ interface
          symtaboffset: aword;
          syms: longword;
          localsyms: longword;
+         symversions: PWord;
+         dynobj: boolean;
          function LoadHeader:word;
          procedure LoadSection(const hdr;index:longint;objdata:TObjData);
          procedure LoadRelocations(const secrec:TSectionRec);
@@ -333,6 +335,9 @@ implementation
       SHT_PREINIT_ARRAY = 16;
       SHT_GROUP    = 17;
       SHT_SYMTAB_SHNDX = 18;
+      SHT_GNU_verdef = $6ffffffd;
+      SHT_GNU_verneed = $6ffffffe;
+      SHT_GNU_versym = $6fffffff;
 
       SHF_WRITE     = 1;
       SHF_ALLOC     = 2;
@@ -1554,6 +1559,8 @@ implementation
           FreeMem(strtab);
         if Assigned(shstrtab) then
           FreeMem(shstrtab);
+        if Assigned(symversions) then
+          FreeMem(symversions);
         inherited Destroy;
       end;
 
@@ -1608,6 +1615,7 @@ implementation
         bind: TAsmSymBind;
         typ: TAsmSymType;
         objsym: TObjSymbol;
+        ver: word;
       begin
         FSymTbl:=AllocMem(count*sizeof(Pointer));
         for i:=1 to count-1 do
@@ -1621,7 +1629,12 @@ implementation
               Continue
             else if sym.st_shndx=SHN_COMMON then
               bind:=AB_COMMON
-            else if (sym.st_shndx>=nsects) or ((sym.st_shndx>0) and (FSecTbl[sym.st_shndx].sec=nil)) then
+            else if (sym.st_shndx>=nsects) or
+              (
+                (sym.st_shndx>0) and
+                (FSecTbl[sym.st_shndx].sec=nil) and
+                (not dynobj)
+              ) then
               begin
                 writeln(objdata.name,' ',i);
                 InternalError(2012060206)
@@ -1660,6 +1673,19 @@ implementation
               writeln(objdata.name,' ',sym.st_info and $0F);
               InternalError(2012060208);
             end;
+            { If reading DSO, we're interested only in global symbols defined there.
+              Symbols with non-current version should also be ignored. }
+            if dynobj then
+              begin
+                if assigned(symversions) then
+                  begin
+                    ver:=symversions[i];
+                    if (ver=0) or (ver > $7FFF) then
+                      continue;
+                  end;
+                if (bind= AB_LOCAL) or (sym.st_shndx=SHN_UNDEF) then
+                  continue;
+              end;
             { validity of name and objsection has been checked above }
             { !! all AT_SECTION symbols have duplicate (null) name,
               therefore TObjSection.CreateSymbol cannot be used here }
@@ -1837,10 +1863,10 @@ implementation
 
     function TElfObjInput.ReadObjData(AReader:TObjectreader;objdata:TObjData):boolean;
       var
-        i,strndx,dynndx: longint;
+        i,j,symtabndx,strndx,dynndx,
+        versymndx,verdefndx,verneedndx: longint;
         objsec: TElfObjSection;
         shdrs: array of TElfsechdr;
-        isdyn: boolean;
       begin
         FReader:=AReader;
         InputFileName:=AReader.FileName;
@@ -1854,7 +1880,7 @@ implementation
             InputError('Not a relocatable or dynamic ELF file');
             exit;
           end;
-        isdyn:=(i=ET_DYN);
+        dynobj:=(i=ET_DYN);
 
         if shentsize<>sizeof(TElfsechdr) then
           InternalError(2012062701);
@@ -1888,13 +1914,11 @@ implementation
           Load the strings, postpone symtable itself until done with sections.
           Note that is is legal to have no symtable.
           For DSO, locate .dynsym instead, this one is near the beginning, but
-          overall number of sections won't be big. Also locate .dynamic. }
-        dynndx:=0;
+          overall number of sections won't be big. }
+        symtabndx:=-1;
         for i:=nsects-1 downto 1 do
           begin
-            if isdyn and (shdrs[i].sh_type=SHT_DYNAMIC) then
-              dynndx:=i;
-            if (shdrs[i].sh_type<>symsectypes[isdyn]) then
+            if (shdrs[i].sh_type<>symsectypes[dynobj]) then
               continue;
             if (shdrs[i].sh_entsize<>sizeof(TElfSymbol)) then
               InternalError(2012060213);
@@ -1913,16 +1937,71 @@ implementation
             localsyms:=shdrs[i].sh_info;
             FLoaded[i]:=True;
             FLoaded[strndx]:=True;
+            symtabndx:=i;
             break;
           end;
 
-        if isdyn then
+        if dynobj then
           begin
+            { Locate .dynamic and version sections. Expect a single one of a kind. }
+            dynndx:=0;
+            versymndx:=0;
+            verdefndx:=0;
+            verneedndx:=0;
+            for i:=nsects-1 downto 0 do
+              begin
+                case shdrs[i].sh_type of
+                  SHT_DYNAMIC:
+                    begin
+                      if dynndx<>0 then
+                        InternalError(2012102001);
+                      dynndx:=i;
+                      if (shdrs[dynndx].sh_link<>strndx) then
+                        InternalError(2012071402);
+                      LoadDynamic(shdrs[dynndx],objdata);
+                    end;
+
+                  SHT_GNU_versym:
+                    begin
+                      if versymndx<>0 then
+                        InternalError(2012102002);
+                      versymndx:=i;
+                      if shdrs[i].sh_entsize<>sizeof(word) then
+                        InternalError(2012102003);
+                      if shdrs[i].sh_link<>symtabndx then
+                        InternalError(2012102004);
+                      if shdrs[i].sh_size<>syms*sizeof(word) then
+                        InternalError(2012102005);
+                      GetMem(symversions,shdrs[i].sh_size);
+                      FReader.seek(shdrs[i].sh_offset);
+                      FReader.read(symversions^,shdrs[i].sh_size);
+                      if source_info.endian<>target_info.endian then
+                        for j:=0 to syms-1 do
+                          SwapEndian(symversions[j]);
+                    end;
+
+                  SHT_GNU_verdef:
+                    begin
+                      if verdefndx<>0 then
+                        InternalError(2012102006);
+                      verdefndx:=i;
+                      //sh_link->.dynstr
+                      //sh_info->.hash
+                    end;
+
+                  SHT_GNU_verneed:
+                    begin
+                      if verneedndx<>0 then
+                        InternalError(2012102007);
+                      verneedndx:=i;
+                      //sh_link->.dynstr
+                      //sh_info->hash
+                    end;
+                end;
+             end;
+
             if dynndx=0 then
               InternalError(2012071401);
-            if (shdrs[dynndx].sh_link<>strndx) then
-              InternalError(2012071402);
-            LoadDynamic(shdrs[dynndx],objdata);
 
             { for DSO, we aren't interested in actual sections, but need to a dummy one
               to maintain integrity. }
@@ -2270,10 +2349,26 @@ implementation
 
 
     procedure TElfExeOutput.Load_DynamicObject(objdata:TObjData);
+      var
+        i: longint;
+        exesym: TExeSymbol;
+        objsym: TObjSymbol;
       begin
         Comment(v_debug,'Dynamic object: '+objdata.name);
         if neededlist.Find(objdata.name)=nil then
           neededlist.Add(objdata.name,objdata);
+        for i:=0 to UnresolvedExeSymbols.Count-1 do
+          begin
+            exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
+            if exesym.State<>symstate_undefined then
+              continue;
+            objsym:=TObjSymbol(objdata.ObjSymbolList.Find(exesym.name));
+            if assigned(objsym) then
+              begin
+                exesym.State:=symstate_defined;
+                exesym.dynindex:=dynsymlist.Add(exesym)+1;
+              end;
+          end;
       end;
 
 
@@ -2339,6 +2434,24 @@ implementation
         objsym:TObjSymbol;
         objsec: TObjSection;
       begin
+        { Unused section removal changes state of referenced exesymbols
+          to symstate_dynamic. Remaining ones can be removed. }
+        for i:=0 to dynsymlist.count-1 do
+          begin
+            exesym:=TExeSymbol(dynsymlist[i]);
+            if assigned(exesym.ObjSymbol.ObjSection) then  // an exported symbol
+              continue;
+            if exesym.state<>symstate_dynamic then
+              begin
+                dynsymlist[i]:=nil;
+                exesym.dynindex:=0;
+              end;
+          end;
+        dynsymlist.Pack;
+        { reindex }
+        for i:=0 to dynsymlist.count-1 do
+          TExeSymbol(dynsymlist[i]).dynindex:=i+1;
+
         { Drop unresolved symbols that aren't referenced, assign dynamic
           indices to remaining ones. }
         for i:=0 to UnresolvedExeSymbols.Count-1 do
@@ -2360,9 +2473,11 @@ implementation
         PrepareGOT;
 
         { Write required PLT entries }
-        for i:=0 to UnresolvedExeSymbols.Count-1 do
+        for i:=0 to dynsymlist.Count-1 do
           begin
-            exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
+            exesym:=TExeSymbol(dynsymlist[i]);
+            if assigned(exesym.ObjSymbol.objsection) then  // an exported symbol
+              continue;
 
             { if there's no PLT references to symbol, then PLT entry isn't needed }
             { !! Does not work correctly yet !! }
@@ -2961,9 +3076,15 @@ implementation
               InternalError(2012071801);
           until exportlist.empty;
 
-        if not (cs_link_staticflag in current_settings.globalswitches) then
-          for i:=0 to UnresolvedExeSymbols.Count-1 do
-            TExeSymbol(UnresolvedExeSymbols[i]).state:=symstate_defined;
+        { Mark unresolved weak symbols as defined, they will become dynamic further on.
+          If compiling a .so, make all symbols dynamic, since shared library may reference
+          symbols from executable which does not participate in linking. }
+        for i:=0 to UnresolvedExeSymbols.Count-1 do
+          begin
+            sym:=TExeSymbol(UnresolvedExeSymbols[i]);
+            if (sym.objsymbol.bind=AB_WEAK_EXTERNAL) or IsSharedLibrary then
+              sym.state:=symstate_defined;
+          end;
       end;