Forráskód Böngészése

+ Enable CPU-specific descendants to write specific dynamic tags.
+ Read version definitions from shared objects.

git-svn-id: trunk@23370 -

sergei 12 éve
szülő
commit
4b925763c3
1 módosított fájl, 96 hozzáadás és 7 törlés
  1. 96 7
      compiler/ogelf.pas

+ 96 - 7
compiler/ogelf.pas

@@ -132,6 +132,7 @@ interface
          localsyms: longword;
          symversions: PWord;
          dynobj: boolean;
+         verdefs: TFPHashObjectList;
          function LoadHeader:word;
          procedure LoadSection(const shdr:TElfsechdr;index:longint;objdata:TObjData);
          procedure LoadRelocations(const secrec:TSectionRec);
@@ -146,6 +147,22 @@ interface
            out secname:string):TElfObjSection;
        end;
 
+       TElfVersionDef = class(TFPHashObject)
+       public
+         index: longword;
+       end;
+
+       TElfDynamicObjData = class(TElfObjData)
+       private
+         FVersionDefs: TFPHashObjectList;
+       public
+         soname_strofs: longword;
+         vernaux_count: longword;
+         constructor create(const n:string);override;
+         destructor destroy;override;
+         property versiondefs:TFPHashObjectList read FVersionDefs;
+       end;
+
        TRelocNameProc=function(reltyp:byte):string;
        TEncodeRelocProc=function(objrel:TObjRelocation):byte;
        TLoadRelocProc=procedure(objrel:TObjRelocation);
@@ -241,8 +258,6 @@ interface
          procedure WriteStaticSymtable;
          procedure InitDynlink;
          procedure PrepareGOT;
-         procedure WriteDynTag(aTag:longword;aValue:longword);
-         procedure WriteDynTag(aTag:longword;aSection:TObjSection;aOffs:aword=0);
        protected
          hastextrelocs: boolean;
          gotsymbol: TObjSymbol;
@@ -264,9 +279,12 @@ interface
          procedure WriteFirstPLTEntry;virtual;abstract;
          procedure WritePLTEntry(exesym:TExeSymbol);virtual;
          procedure WriteIndirectPLTEntry(exesym:TExeSymbol);virtual;
+         procedure WriteTargetDynamicTags;virtual;
          procedure GOTRelocPass1(objsec:TObjSection;var idx:longint);virtual;abstract;
          procedure ReportNonDSOReloc(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);
          procedure ReportRelocOverflow(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);
+         procedure WriteDynTag(aTag:longword;aValue:longword);
+         procedure WriteDynTag(aTag:longword;aSection:TObjSection;aOffs:aword=0);
        public
          constructor Create;override;
          destructor Destroy;override;
@@ -853,6 +871,27 @@ implementation
       end;
 
 
+{****************************************************************************
+                            TElfDynamicObjData
+****************************************************************************}
+
+    constructor TElfDynamicObjData.create(const n:string);
+      begin
+        inherited Create(n);
+        FVersionDefs:=TFPHashObjectList.create(true);
+        { Default symversions with indices 0 and 1 }
+        TElfVersionDef.create(FVersionDefs,'*local*');
+        TElfVersionDef.create(FVersionDefs,'*global*');
+      end;
+
+
+    destructor TElfDynamicObjData.destroy;
+      begin
+        FVersionDefs.free;
+        inherited Destroy;
+      end;
+
+
 {****************************************************************************
                             TElfSymtab
 ****************************************************************************}
@@ -1371,6 +1410,7 @@ implementation
             end;
             { If reading DSO, we're interested only in global symbols defined there.
               Symbols with non-current version should also be ignored. }
+            ver:=0;
             if dynobj then
               begin
                 if assigned(symversions) then
@@ -1381,6 +1421,8 @@ implementation
                   end;
                 if (bind=AB_LOCAL) or (sym.st_shndx=SHN_UNDEF) then
                   continue;
+                if ver>=verdefs.count then
+                  InternalError(2012120505);
               end;
             { validity of name and objsection has been checked above }
             { !! all AT_SECTION symbols have duplicate (null) name,
@@ -1604,6 +1646,9 @@ implementation
         grp: TObjSectionGroup;
         tmp: longword;
         count: longint;
+        vd: TElfverdef;
+        vda: TElfverdaux;
+        vdoffset: aword;
       begin
         FReader:=AReader;
         InputFileName:=AReader.FileName;
@@ -1622,7 +1667,13 @@ implementation
         if shentsize<>sizeof(TElfsechdr) then
           InternalError(2012062701);
 
-        objdata:=CObjData.Create(InputFilename);
+        if dynobj then
+          begin
+            objdata:=TElfDynamicObjData.Create(InputFilename);
+            verdefs:=TElfDynamicObjData(objdata).versiondefs;
+          end
+        else
+          objdata:=CObjData.Create(InputFilename);
 
         FSecTbl:=AllocMem(nsects*sizeof(TSectionRec));
         FLoaded:=AllocMem(nsects*sizeof(boolean));
@@ -1726,8 +1777,34 @@ implementation
                       if verdefndx<>0 then
                         InternalError(2012102006);
                       verdefndx:=i;
-                      //sh_link->.dynstr
-                      //sh_info->.hash
+                      if shdrs[i].sh_link<>strndx then
+                        InternalError(2012120501);
+                      vdoffset:=shdrs[i].sh_offset;
+                      { TODO: can we rely on sh_info, or must read until vd_next=0? }
+                      for j:=1 to shdrs[i].sh_info do
+                        begin
+                          FReader.seek(vdoffset);
+                          FReader.Read(vd,sizeof(TElfverdef));
+                          MaybeSwapElfverdef(vd);
+                          if vd.vd_version<>VER_DEF_CURRENT then
+                            InternalError(2012120502);
+                          FReader.seek(vdoffset+vd.vd_aux);
+                          vdoffset:=vdoffset+vd.vd_next;
+                          { First verdaux entry holds name of version (unless VER_FLG_BASE flag is set),
+                            subsequent one(s) point to parent(s). For our purposes, version hierarchy
+                            looks irrelevant. }
+                          FReader.Read(vda,sizeof(TElfverdaux));
+                          MaybeSwapElfverdaux(vda);
+                          if vda.vda_name>=strtablen then
+                            InternalError(2012120503);
+                          if (vd.vd_flags and VER_FLG_BASE)<>0 then
+                            continue;
+                          { Assuming verdef indices assigned continuously starting from 2,
+                            at least BFD produces files that way. }
+                          if verdefs.count<>vd.vd_ndx then
+                            InternalError(2012120504);
+                          TElfVersionDef.Create(verdefs,string(PChar(@strtab[vda.vda_name])));
+                        end;
                     end;
 
                   SHT_GNU_verneed:
@@ -1736,7 +1813,7 @@ implementation
                         InternalError(2012102007);
                       verneedndx:=i;
                       //sh_link->.dynstr
-                      //sh_info->hash
+                      //sh_info->number of entries
                     end;
                 end;
              end;
@@ -2779,16 +2856,25 @@ implementation
       end;
 
 
+    procedure TElfExeOutput.WriteTargetDynamicTags;
+      begin
+        { to be overridden by CPU-specific descendants }
+      end;
+
+
     procedure TElfExeOutput.WriteDynamicTags;
       var
         s: aword;
         i: longint;
         sym: TExeSymbol;
         hs:string;
+        dynobj: TElfDynamicObjData;
       begin
         for i:=0 to neededlist.Count-1 do
           begin
-            s:=dynsymtable.fstrsec.writestr(neededlist.NameOfIndex(i));
+            dynobj:=TElfDynamicObjData(neededlist[i]);
+            s:=dynsymtable.fstrsec.writestr(dynobj.name);
+            dynobj.soname_strofs:=s;
             WriteDynTag(DT_NEEDED,s);
           end;
 
@@ -2863,6 +2949,9 @@ implementation
             if (relative_reloc_count>0) then
               writeDynTag(relcnttags[rela],relative_reloc_count);
           end;
+
+        WriteTargetDynamicTags;
+
         if (verdefcount>0) or (verneedcount>0) then
           begin
             if (verdefcount>0) then