mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-04 19:50:54 +02:00
+ 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:
parent
82fd77d341
commit
1aea22a6ca
@ -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
|
||||
|
@ -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]);
|
||||
|
Loading…
Reference in New Issue
Block a user