Browse Source

+ Internal linker: generic and ELF-specific support for grouped sections, allow same symbol to be defined in several COMDAT groups.
* ELF linker: don't make unresolved weak symbols dynamic if linking statically (-Xt in command line).
* Now internal linker produces working executable for tw14265 also on i386-linux when compiling manually (still unable to locate required libraries when run from test suite).

git-svn-id: trunk@22987 -

sergei 12 years ago
parent
commit
1aea22a6ca
2 changed files with 130 additions and 10 deletions
  1. 50 0
      compiler/ogbase.pas
  2. 80 10
      compiler/ogelf.pas

+ 50 - 0
compiler/ogbase.pas

@@ -201,6 +201,8 @@ interface
         property typ: TObjRelocationType read GetType write SetType;
      end;
 
+     TObjSectionGroup = class;
+
      TObjSection = class(TFPHashObject)
      private
        FData       : TDynamicArray;
@@ -216,6 +218,7 @@ interface
        Size,
        DataPos,
        MemPos     : aword;
+       Group      : TObjSectionGroup;
        DataAlignBytes : shortint;
        { Relocations (=references) to other sections }
        ObjRelocations : TFPObjectList;
@@ -245,6 +248,12 @@ interface
      end;
      TObjSectionClass = class of TObjSection;
 
+     TObjSectionGroup = class(TFPHashObject)
+     public
+       members: array of TObjSection;
+       iscomdat: boolean;
+     end;
+
      TString80 = string[80];
 
      TObjData = class(TLinkedListItem)
@@ -258,6 +267,7 @@ interface
        { Special info sections that are written to during object generation }
        FStabsObjSec,
        FStabStrObjSec : TObjSection;
+       FGroupsList : TFPHashObjectList;
        procedure section_reset(p:TObject;arg:pointer);
        procedure section_afteralloc(p:TObject;arg:pointer);
        procedure section_afterwrite(p:TObject;arg:pointer);
@@ -275,6 +285,7 @@ interface
        function  sectiontype2align(atype:TAsmSectiontype):shortint;virtual;
        function  createsection(atype:TAsmSectionType;const aname:string='';aorder:TAsmSectionOrder=secorder_default):TObjSection;
        function  createsection(const aname:string;aalign:shortint;aoptions:TObjSectionOptions;DiscardDuplicate:boolean=true):TObjSection;virtual;
+       function  createsectiongroup(const aname:string):TObjSectionGroup;
        procedure CreateDebugSections;virtual;
        function  findsection(const aname:string):TObjSection;
        procedure setsection(asec:TObjSection);
@@ -300,6 +311,7 @@ interface
        property CurrObjSec:TObjSection read FCurrObjSec;
        property ObjSymbolList:TFPHashObjectList read FObjSymbolList;
        property ObjSectionList:TFPHashObjectList read FObjSectionList;
+       property GroupsList:TFPHashObjectList read FGroupsList;
        property StabsSec:TObjSection read FStabsObjSec write FStabsObjSec;
        property StabStrSec:TObjSection read FStabStrObjSec write FStabStrObjSec;
      end;
@@ -483,6 +495,7 @@ interface
         EntrySym  : TObjSymbol;
         SectionDataAlign,
         SectionMemAlign : aword;
+        ComdatGroups : TFPHashList;
         FixedSectionAlign : boolean;
         function  writeData:boolean;virtual;abstract;
         property CExeSection:TExeSectionClass read FCExeSection write FCExeSection;
@@ -938,6 +951,8 @@ implementation
 {$ifdef MEMDEBUG}
         MemObjSymbols.Stop;
 {$endif}
+        GroupsList.free;
+
         { Sections }
 {$ifdef MEMDEBUG}
         MemObjSections.Start;
@@ -1073,6 +1088,14 @@ implementation
       end;
 
 
+    function TObjData.CreateSectionGroup(const aname:string):TObjSectionGroup;
+      begin
+        if FGroupsList=nil then
+          FGroupsList:=TFPHashObjectList.Create(true);
+        result:=TObjSectionGroup.Create(FGroupsList,aname);
+      end;
+
+
     procedure TObjData.CreateDebugSections;
       begin
       end;
@@ -1638,6 +1661,7 @@ implementation
         FProvidedObjSymbols:=TFPObjectList.Create(false);
         FIndirectObjSymbols:=TFPObjectList.Create(false);
         FExeVTableList:=TFPObjectList.Create(false);
+        ComdatGroups:=TFPHashList.Create;
         { sections }
         FExeSectionList:=TFPHashObjectList.Create(true);
         FImageBase:=0;
@@ -1664,6 +1688,7 @@ implementation
         CommonObjSymbols.free;
         ExeVTableList.free;
         FExeSectionList.free;
+        ComdatGroups.free;
         ObjDatalist.free;
         FWriter.free;
         inherited destroy;
@@ -2229,6 +2254,7 @@ implementation
           hs     : string;
           exesym : TExeSymbol;
           objsym : TObjSymbol;
+          grp    : TObjSectionGroup;
         begin
           for j:=0 to ObjData.ObjSymbolList.Count-1 do
             begin
@@ -2256,6 +2282,30 @@ implementation
                     end;
                   continue;
                 end;
+
+              { If this symbol comes from COMDAT group, see if a group with
+                matching signature is already included. }
+              if assigned(objsym.objsection) and
+                 assigned(objsym.objsection.group) then
+                begin
+                  grp:=objsym.objsection.group;
+                  if grp.IsComdat then
+                    begin
+                      if ComdatGroups.Find(grp.name)=nil then
+                        ComdatGroups.Add(grp.name,grp)
+                      else
+                        begin
+                          { Undefine the symbol, causing relocations to it from same
+                            objdata to be redirected to the symbol in the actually
+                            linked group. }
+                          if objsym.bind=AB_GLOBAL then
+                            objsym.bind:=AB_EXTERNAL;
+                          { AB_WEAK_EXTERNAL remains unchanged }
+                          objsym.objsection:=nil;
+                        end;
+                    end;
+                end;
+
               { Search for existing exesymbol }
               exesym:=texesymbol(FExeSymbolList.Find(objsym.name));
               if not assigned(exesym) then

+ 80 - 10
compiler/ogelf.pas

@@ -440,6 +440,8 @@ implementation
       DT_VERNEED   = $6ffffffe;
       DT_VERNEEDNUM = $6fffffff;
 
+      GRP_COMDAT = 1;
+
       type
       { Structures which are written directly to the output file }
         TElf32header=packed record
@@ -1653,6 +1655,7 @@ implementation
       var
         shdr: TElfsechdr absolute hdr;
         sec: TElfObjSection;
+        sym: TElfSymbol;
         secname: string;
       begin
         case shdr.sh_type of
@@ -1718,13 +1721,39 @@ implementation
               (shdr.sh_entsize=sizeof(longword)) and
               ((shdr.sh_size mod shdr.sh_entsize)=0) then
               begin
-                { we need a dummy section to load the corresponding symbol later on }
-                secname:=string(PChar(@shstrtab[shdr.sh_name]));
-                sec:=TElfObjSection.create_ext(objdata,secname,
-                  shdr.sh_type,shdr.sh_flags,shdr.sh_addralign,shdr.sh_entsize);
-                sec.index:=index;
-                FSecTbl[index].sec:=sec;
-              end;
+                { Groups are identified by name of symbol pointed to by
+                  sh_link and sh_info, not by sh_name. This symbol
+                  may as well be STT_SECTION symbol of this section,
+                  in which case we end up using sh_name. }
+                if dynobj then
+                  InternalError(2012110801);
+                if (shdr.sh_link<>symtabndx) then
+                  InternalError(2012110703);
+                if (shdr.sh_info>=syms) then
+                  InternalError(2012110704);
+
+                FReader.Seek(symtaboffset+shdr.sh_info*sizeof(TElfSymbol));
+                FReader.Read(sym,sizeof(TElfSymbol));
+                MaybeSwapElfSymbol(sym);
+                if sym.st_name>=strtablen then
+                  InternalError(2012110705);
+                if (sym.st_shndx=index) and (sym.st_info=((STB_LOCAL shl 4) or STT_SECTION)) then
+                  secname:=string(PChar(@shstrtab[shdr.sh_name]))
+                else
+                  secname:=string(PChar(@strtab[sym.st_name]));
+
+                { Postpone further processing until all sections are loaded,
+                  we'll need to access correct section header.
+                  Since ABI requires SHT_GROUP sections to come first in the file,
+                  we assume that group number x has header index x+1.
+                  If we ever encounter files where this is not true, we'll have
+                  to maintain a separate index. }
+                objdata.CreateSectionGroup(secname);
+                if (index<>objdata.GroupsList.Count) then
+                  InternalError(2012110802);
+              end
+            else
+              InternalError(2012110706);
         else
           InternalError(2012072603);
         end;
@@ -1813,8 +1842,11 @@ implementation
       var
         i,j,strndx,dynndx,
         versymndx,verdefndx,verneedndx: longint;
-        objsec: TElfObjSection;
+        objsec: TObjSection;
         shdrs: array of TElfsechdr;
+        grp: TObjSectionGroup;
+        tmp: longword;
+        count: longint;
       begin
         FReader:=AReader;
         InputFileName:=AReader.FileName;
@@ -1986,7 +2018,7 @@ implementation
         { finish relocations }
         for i:=0 to objdata.ObjSectionList.Count-1 do
           begin
-            objsec:=TElfObjSection(objdata.ObjsectionList[i]);
+            objsec:=TObjSection(objdata.ObjsectionList[i]);
             { skip debug sections }
             if (oso_debug in objsec.SecOptions) and
                (cs_link_strip in current_settings.globalswitches) and
@@ -1997,6 +2029,40 @@ implementation
               LoadRelocations(FSecTbl[objsec.index]);
           end;
 
+        { finish processing section groups, if any }
+        if Assigned(objdata.GroupsList) then
+          begin
+            for i:=0 to objdata.GroupsList.Count-1 do
+              begin
+                grp:=TObjSectionGroup(objData.GroupsList[i]);
+                FReader.Seek(shdrs[i+1].sh_offset);
+                { first dword is flags }
+                FReader.Read(tmp,sizeof(longword));
+                if source_info.endian<>target_info.endian then
+                  tmp:=SwapEndian(tmp);
+                if (tmp and GRP_COMDAT)<>0 then
+                  grp.IsComdat:=true;
+
+                count:=(shdrs[i+1].sh_size div sizeof(longword))-1;
+                SetLength(grp.members,count);
+                for j:=0 to count-1 do
+                  begin
+                    FReader.Read(tmp,sizeof(longword));
+                    if source_info.endian<>target_info.endian then
+                      tmp:=SwapEndian(tmp);
+                    if (tmp>=nsects) then
+                      InternalError(2012110805);
+                    objsec:=FSecTbl[tmp].sec;
+                    if (objsec=nil) then
+                      InternalError(2012110806);
+                    if (TElfObjSection(objsec).shflags and SHF_GROUP)=0 then
+                      InternalError(2012110807);
+                    grp.members[j]:=objsec;
+                    objsec.Group:=grp;
+                  end;
+              end;
+          end;
+
         result:=True;
       end;
 
@@ -2405,7 +2471,11 @@ implementation
           TExeSymbol(dynsymlist[i]).dynindex:=i+1;
 
         { Drop unresolved symbols that aren't referenced, assign dynamic
-          indices to remaining ones. }
+          indices to remaining ones, but not if linking with -Xt.
+          TODO: behavior of .so with -Xt ? }
+        if (cs_link_staticflag in current_settings.globalswitches) then
+          UnresolvedExeSymbols.Clear
+        else
         for i:=0 to UnresolvedExeSymbols.Count-1 do
           begin
             exesym:=TExeSymbol(UnresolvedExeSymbols[i]);