mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-08 12:39:39 +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;
|
property typ: TObjRelocationType read GetType write SetType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TObjSectionGroup = class;
|
||||||
|
|
||||||
TObjSection = class(TFPHashObject)
|
TObjSection = class(TFPHashObject)
|
||||||
private
|
private
|
||||||
FData : TDynamicArray;
|
FData : TDynamicArray;
|
||||||
@ -216,6 +218,7 @@ interface
|
|||||||
Size,
|
Size,
|
||||||
DataPos,
|
DataPos,
|
||||||
MemPos : aword;
|
MemPos : aword;
|
||||||
|
Group : TObjSectionGroup;
|
||||||
DataAlignBytes : shortint;
|
DataAlignBytes : shortint;
|
||||||
{ Relocations (=references) to other sections }
|
{ Relocations (=references) to other sections }
|
||||||
ObjRelocations : TFPObjectList;
|
ObjRelocations : TFPObjectList;
|
||||||
@ -245,6 +248,12 @@ interface
|
|||||||
end;
|
end;
|
||||||
TObjSectionClass = class of TObjSection;
|
TObjSectionClass = class of TObjSection;
|
||||||
|
|
||||||
|
TObjSectionGroup = class(TFPHashObject)
|
||||||
|
public
|
||||||
|
members: array of TObjSection;
|
||||||
|
iscomdat: boolean;
|
||||||
|
end;
|
||||||
|
|
||||||
TString80 = string[80];
|
TString80 = string[80];
|
||||||
|
|
||||||
TObjData = class(TLinkedListItem)
|
TObjData = class(TLinkedListItem)
|
||||||
@ -258,6 +267,7 @@ interface
|
|||||||
{ Special info sections that are written to during object generation }
|
{ Special info sections that are written to during object generation }
|
||||||
FStabsObjSec,
|
FStabsObjSec,
|
||||||
FStabStrObjSec : TObjSection;
|
FStabStrObjSec : TObjSection;
|
||||||
|
FGroupsList : TFPHashObjectList;
|
||||||
procedure section_reset(p:TObject;arg:pointer);
|
procedure section_reset(p:TObject;arg:pointer);
|
||||||
procedure section_afteralloc(p:TObject;arg:pointer);
|
procedure section_afteralloc(p:TObject;arg:pointer);
|
||||||
procedure section_afterwrite(p:TObject;arg:pointer);
|
procedure section_afterwrite(p:TObject;arg:pointer);
|
||||||
@ -275,6 +285,7 @@ interface
|
|||||||
function sectiontype2align(atype:TAsmSectiontype):shortint;virtual;
|
function sectiontype2align(atype:TAsmSectiontype):shortint;virtual;
|
||||||
function createsection(atype:TAsmSectionType;const aname:string='';aorder:TAsmSectionOrder=secorder_default):TObjSection;
|
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 createsection(const aname:string;aalign:shortint;aoptions:TObjSectionOptions;DiscardDuplicate:boolean=true):TObjSection;virtual;
|
||||||
|
function createsectiongroup(const aname:string):TObjSectionGroup;
|
||||||
procedure CreateDebugSections;virtual;
|
procedure CreateDebugSections;virtual;
|
||||||
function findsection(const aname:string):TObjSection;
|
function findsection(const aname:string):TObjSection;
|
||||||
procedure setsection(asec:TObjSection);
|
procedure setsection(asec:TObjSection);
|
||||||
@ -300,6 +311,7 @@ interface
|
|||||||
property CurrObjSec:TObjSection read FCurrObjSec;
|
property CurrObjSec:TObjSection read FCurrObjSec;
|
||||||
property ObjSymbolList:TFPHashObjectList read FObjSymbolList;
|
property ObjSymbolList:TFPHashObjectList read FObjSymbolList;
|
||||||
property ObjSectionList:TFPHashObjectList read FObjSectionList;
|
property ObjSectionList:TFPHashObjectList read FObjSectionList;
|
||||||
|
property GroupsList:TFPHashObjectList read FGroupsList;
|
||||||
property StabsSec:TObjSection read FStabsObjSec write FStabsObjSec;
|
property StabsSec:TObjSection read FStabsObjSec write FStabsObjSec;
|
||||||
property StabStrSec:TObjSection read FStabStrObjSec write FStabStrObjSec;
|
property StabStrSec:TObjSection read FStabStrObjSec write FStabStrObjSec;
|
||||||
end;
|
end;
|
||||||
@ -483,6 +495,7 @@ interface
|
|||||||
EntrySym : TObjSymbol;
|
EntrySym : TObjSymbol;
|
||||||
SectionDataAlign,
|
SectionDataAlign,
|
||||||
SectionMemAlign : aword;
|
SectionMemAlign : aword;
|
||||||
|
ComdatGroups : TFPHashList;
|
||||||
FixedSectionAlign : boolean;
|
FixedSectionAlign : boolean;
|
||||||
function writeData:boolean;virtual;abstract;
|
function writeData:boolean;virtual;abstract;
|
||||||
property CExeSection:TExeSectionClass read FCExeSection write FCExeSection;
|
property CExeSection:TExeSectionClass read FCExeSection write FCExeSection;
|
||||||
@ -938,6 +951,8 @@ implementation
|
|||||||
{$ifdef MEMDEBUG}
|
{$ifdef MEMDEBUG}
|
||||||
MemObjSymbols.Stop;
|
MemObjSymbols.Stop;
|
||||||
{$endif}
|
{$endif}
|
||||||
|
GroupsList.free;
|
||||||
|
|
||||||
{ Sections }
|
{ Sections }
|
||||||
{$ifdef MEMDEBUG}
|
{$ifdef MEMDEBUG}
|
||||||
MemObjSections.Start;
|
MemObjSections.Start;
|
||||||
@ -1073,6 +1088,14 @@ implementation
|
|||||||
end;
|
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;
|
procedure TObjData.CreateDebugSections;
|
||||||
begin
|
begin
|
||||||
end;
|
end;
|
||||||
@ -1638,6 +1661,7 @@ implementation
|
|||||||
FProvidedObjSymbols:=TFPObjectList.Create(false);
|
FProvidedObjSymbols:=TFPObjectList.Create(false);
|
||||||
FIndirectObjSymbols:=TFPObjectList.Create(false);
|
FIndirectObjSymbols:=TFPObjectList.Create(false);
|
||||||
FExeVTableList:=TFPObjectList.Create(false);
|
FExeVTableList:=TFPObjectList.Create(false);
|
||||||
|
ComdatGroups:=TFPHashList.Create;
|
||||||
{ sections }
|
{ sections }
|
||||||
FExeSectionList:=TFPHashObjectList.Create(true);
|
FExeSectionList:=TFPHashObjectList.Create(true);
|
||||||
FImageBase:=0;
|
FImageBase:=0;
|
||||||
@ -1664,6 +1688,7 @@ implementation
|
|||||||
CommonObjSymbols.free;
|
CommonObjSymbols.free;
|
||||||
ExeVTableList.free;
|
ExeVTableList.free;
|
||||||
FExeSectionList.free;
|
FExeSectionList.free;
|
||||||
|
ComdatGroups.free;
|
||||||
ObjDatalist.free;
|
ObjDatalist.free;
|
||||||
FWriter.free;
|
FWriter.free;
|
||||||
inherited destroy;
|
inherited destroy;
|
||||||
@ -2229,6 +2254,7 @@ implementation
|
|||||||
hs : string;
|
hs : string;
|
||||||
exesym : TExeSymbol;
|
exesym : TExeSymbol;
|
||||||
objsym : TObjSymbol;
|
objsym : TObjSymbol;
|
||||||
|
grp : TObjSectionGroup;
|
||||||
begin
|
begin
|
||||||
for j:=0 to ObjData.ObjSymbolList.Count-1 do
|
for j:=0 to ObjData.ObjSymbolList.Count-1 do
|
||||||
begin
|
begin
|
||||||
@ -2256,6 +2282,30 @@ implementation
|
|||||||
end;
|
end;
|
||||||
continue;
|
continue;
|
||||||
end;
|
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 }
|
{ Search for existing exesymbol }
|
||||||
exesym:=texesymbol(FExeSymbolList.Find(objsym.name));
|
exesym:=texesymbol(FExeSymbolList.Find(objsym.name));
|
||||||
if not assigned(exesym) then
|
if not assigned(exesym) then
|
||||||
|
@ -440,6 +440,8 @@ implementation
|
|||||||
DT_VERNEED = $6ffffffe;
|
DT_VERNEED = $6ffffffe;
|
||||||
DT_VERNEEDNUM = $6fffffff;
|
DT_VERNEEDNUM = $6fffffff;
|
||||||
|
|
||||||
|
GRP_COMDAT = 1;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ Structures which are written directly to the output file }
|
{ Structures which are written directly to the output file }
|
||||||
TElf32header=packed record
|
TElf32header=packed record
|
||||||
@ -1653,6 +1655,7 @@ implementation
|
|||||||
var
|
var
|
||||||
shdr: TElfsechdr absolute hdr;
|
shdr: TElfsechdr absolute hdr;
|
||||||
sec: TElfObjSection;
|
sec: TElfObjSection;
|
||||||
|
sym: TElfSymbol;
|
||||||
secname: string;
|
secname: string;
|
||||||
begin
|
begin
|
||||||
case shdr.sh_type of
|
case shdr.sh_type of
|
||||||
@ -1718,13 +1721,39 @@ implementation
|
|||||||
(shdr.sh_entsize=sizeof(longword)) and
|
(shdr.sh_entsize=sizeof(longword)) and
|
||||||
((shdr.sh_size mod shdr.sh_entsize)=0) then
|
((shdr.sh_size mod shdr.sh_entsize)=0) then
|
||||||
begin
|
begin
|
||||||
{ we need a dummy section to load the corresponding symbol later on }
|
{ Groups are identified by name of symbol pointed to by
|
||||||
secname:=string(PChar(@shstrtab[shdr.sh_name]));
|
sh_link and sh_info, not by sh_name. This symbol
|
||||||
sec:=TElfObjSection.create_ext(objdata,secname,
|
may as well be STT_SECTION symbol of this section,
|
||||||
shdr.sh_type,shdr.sh_flags,shdr.sh_addralign,shdr.sh_entsize);
|
in which case we end up using sh_name. }
|
||||||
sec.index:=index;
|
if dynobj then
|
||||||
FSecTbl[index].sec:=sec;
|
InternalError(2012110801);
|
||||||
end;
|
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
|
else
|
||||||
InternalError(2012072603);
|
InternalError(2012072603);
|
||||||
end;
|
end;
|
||||||
@ -1813,8 +1842,11 @@ implementation
|
|||||||
var
|
var
|
||||||
i,j,strndx,dynndx,
|
i,j,strndx,dynndx,
|
||||||
versymndx,verdefndx,verneedndx: longint;
|
versymndx,verdefndx,verneedndx: longint;
|
||||||
objsec: TElfObjSection;
|
objsec: TObjSection;
|
||||||
shdrs: array of TElfsechdr;
|
shdrs: array of TElfsechdr;
|
||||||
|
grp: TObjSectionGroup;
|
||||||
|
tmp: longword;
|
||||||
|
count: longint;
|
||||||
begin
|
begin
|
||||||
FReader:=AReader;
|
FReader:=AReader;
|
||||||
InputFileName:=AReader.FileName;
|
InputFileName:=AReader.FileName;
|
||||||
@ -1986,7 +2018,7 @@ implementation
|
|||||||
{ finish relocations }
|
{ finish relocations }
|
||||||
for i:=0 to objdata.ObjSectionList.Count-1 do
|
for i:=0 to objdata.ObjSectionList.Count-1 do
|
||||||
begin
|
begin
|
||||||
objsec:=TElfObjSection(objdata.ObjsectionList[i]);
|
objsec:=TObjSection(objdata.ObjsectionList[i]);
|
||||||
{ skip debug sections }
|
{ skip debug sections }
|
||||||
if (oso_debug in objsec.SecOptions) and
|
if (oso_debug in objsec.SecOptions) and
|
||||||
(cs_link_strip in current_settings.globalswitches) and
|
(cs_link_strip in current_settings.globalswitches) and
|
||||||
@ -1997,6 +2029,40 @@ implementation
|
|||||||
LoadRelocations(FSecTbl[objsec.index]);
|
LoadRelocations(FSecTbl[objsec.index]);
|
||||||
end;
|
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;
|
result:=True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2405,7 +2471,11 @@ implementation
|
|||||||
TExeSymbol(dynsymlist[i]).dynindex:=i+1;
|
TExeSymbol(dynsymlist[i]).dynindex:=i+1;
|
||||||
|
|
||||||
{ Drop unresolved symbols that aren't referenced, assign dynamic
|
{ 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
|
for i:=0 to UnresolvedExeSymbols.Count-1 do
|
||||||
begin
|
begin
|
||||||
exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
|
exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
|
||||||
|
Loading…
Reference in New Issue
Block a user