+ 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 -
This commit is contained in:
sergei 2012-11-15 13:41:25 +00:00
parent 82fd77d341
commit 1aea22a6ca
2 changed files with 130 additions and 10 deletions

View File

@ -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

View File

@ -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]);