mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-18 19:09:27 +02:00
* ELF linker: improved dynamic symbol handling.
+ Read .gnu.version sections and ignore local symbols and symbols with non-current version. + Check that external symbols are actually present in dynamic objects. git-svn-id: trunk@22832 -
This commit is contained in:
parent
f94ba86bb9
commit
6023f73e2a
@ -125,6 +125,8 @@ interface
|
|||||||
symtaboffset: aword;
|
symtaboffset: aword;
|
||||||
syms: longword;
|
syms: longword;
|
||||||
localsyms: longword;
|
localsyms: longword;
|
||||||
|
symversions: PWord;
|
||||||
|
dynobj: boolean;
|
||||||
function LoadHeader:word;
|
function LoadHeader:word;
|
||||||
procedure LoadSection(const hdr;index:longint;objdata:TObjData);
|
procedure LoadSection(const hdr;index:longint;objdata:TObjData);
|
||||||
procedure LoadRelocations(const secrec:TSectionRec);
|
procedure LoadRelocations(const secrec:TSectionRec);
|
||||||
@ -333,6 +335,9 @@ implementation
|
|||||||
SHT_PREINIT_ARRAY = 16;
|
SHT_PREINIT_ARRAY = 16;
|
||||||
SHT_GROUP = 17;
|
SHT_GROUP = 17;
|
||||||
SHT_SYMTAB_SHNDX = 18;
|
SHT_SYMTAB_SHNDX = 18;
|
||||||
|
SHT_GNU_verdef = $6ffffffd;
|
||||||
|
SHT_GNU_verneed = $6ffffffe;
|
||||||
|
SHT_GNU_versym = $6fffffff;
|
||||||
|
|
||||||
SHF_WRITE = 1;
|
SHF_WRITE = 1;
|
||||||
SHF_ALLOC = 2;
|
SHF_ALLOC = 2;
|
||||||
@ -1554,6 +1559,8 @@ implementation
|
|||||||
FreeMem(strtab);
|
FreeMem(strtab);
|
||||||
if Assigned(shstrtab) then
|
if Assigned(shstrtab) then
|
||||||
FreeMem(shstrtab);
|
FreeMem(shstrtab);
|
||||||
|
if Assigned(symversions) then
|
||||||
|
FreeMem(symversions);
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1608,6 +1615,7 @@ implementation
|
|||||||
bind: TAsmSymBind;
|
bind: TAsmSymBind;
|
||||||
typ: TAsmSymType;
|
typ: TAsmSymType;
|
||||||
objsym: TObjSymbol;
|
objsym: TObjSymbol;
|
||||||
|
ver: word;
|
||||||
begin
|
begin
|
||||||
FSymTbl:=AllocMem(count*sizeof(Pointer));
|
FSymTbl:=AllocMem(count*sizeof(Pointer));
|
||||||
for i:=1 to count-1 do
|
for i:=1 to count-1 do
|
||||||
@ -1621,7 +1629,12 @@ implementation
|
|||||||
Continue
|
Continue
|
||||||
else if sym.st_shndx=SHN_COMMON then
|
else if sym.st_shndx=SHN_COMMON then
|
||||||
bind:=AB_COMMON
|
bind:=AB_COMMON
|
||||||
else if (sym.st_shndx>=nsects) or ((sym.st_shndx>0) and (FSecTbl[sym.st_shndx].sec=nil)) then
|
else if (sym.st_shndx>=nsects) or
|
||||||
|
(
|
||||||
|
(sym.st_shndx>0) and
|
||||||
|
(FSecTbl[sym.st_shndx].sec=nil) and
|
||||||
|
(not dynobj)
|
||||||
|
) then
|
||||||
begin
|
begin
|
||||||
writeln(objdata.name,' ',i);
|
writeln(objdata.name,' ',i);
|
||||||
InternalError(2012060206)
|
InternalError(2012060206)
|
||||||
@ -1660,6 +1673,19 @@ implementation
|
|||||||
writeln(objdata.name,' ',sym.st_info and $0F);
|
writeln(objdata.name,' ',sym.st_info and $0F);
|
||||||
InternalError(2012060208);
|
InternalError(2012060208);
|
||||||
end;
|
end;
|
||||||
|
{ If reading DSO, we're interested only in global symbols defined there.
|
||||||
|
Symbols with non-current version should also be ignored. }
|
||||||
|
if dynobj then
|
||||||
|
begin
|
||||||
|
if assigned(symversions) then
|
||||||
|
begin
|
||||||
|
ver:=symversions[i];
|
||||||
|
if (ver=0) or (ver > $7FFF) then
|
||||||
|
continue;
|
||||||
|
end;
|
||||||
|
if (bind= AB_LOCAL) or (sym.st_shndx=SHN_UNDEF) then
|
||||||
|
continue;
|
||||||
|
end;
|
||||||
{ validity of name and objsection has been checked above }
|
{ validity of name and objsection has been checked above }
|
||||||
{ !! all AT_SECTION symbols have duplicate (null) name,
|
{ !! all AT_SECTION symbols have duplicate (null) name,
|
||||||
therefore TObjSection.CreateSymbol cannot be used here }
|
therefore TObjSection.CreateSymbol cannot be used here }
|
||||||
@ -1837,10 +1863,10 @@ implementation
|
|||||||
|
|
||||||
function TElfObjInput.ReadObjData(AReader:TObjectreader;objdata:TObjData):boolean;
|
function TElfObjInput.ReadObjData(AReader:TObjectreader;objdata:TObjData):boolean;
|
||||||
var
|
var
|
||||||
i,strndx,dynndx: longint;
|
i,j,symtabndx,strndx,dynndx,
|
||||||
|
versymndx,verdefndx,verneedndx: longint;
|
||||||
objsec: TElfObjSection;
|
objsec: TElfObjSection;
|
||||||
shdrs: array of TElfsechdr;
|
shdrs: array of TElfsechdr;
|
||||||
isdyn: boolean;
|
|
||||||
begin
|
begin
|
||||||
FReader:=AReader;
|
FReader:=AReader;
|
||||||
InputFileName:=AReader.FileName;
|
InputFileName:=AReader.FileName;
|
||||||
@ -1854,7 +1880,7 @@ implementation
|
|||||||
InputError('Not a relocatable or dynamic ELF file');
|
InputError('Not a relocatable or dynamic ELF file');
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
isdyn:=(i=ET_DYN);
|
dynobj:=(i=ET_DYN);
|
||||||
|
|
||||||
if shentsize<>sizeof(TElfsechdr) then
|
if shentsize<>sizeof(TElfsechdr) then
|
||||||
InternalError(2012062701);
|
InternalError(2012062701);
|
||||||
@ -1888,13 +1914,11 @@ implementation
|
|||||||
Load the strings, postpone symtable itself until done with sections.
|
Load the strings, postpone symtable itself until done with sections.
|
||||||
Note that is is legal to have no symtable.
|
Note that is is legal to have no symtable.
|
||||||
For DSO, locate .dynsym instead, this one is near the beginning, but
|
For DSO, locate .dynsym instead, this one is near the beginning, but
|
||||||
overall number of sections won't be big. Also locate .dynamic. }
|
overall number of sections won't be big. }
|
||||||
dynndx:=0;
|
symtabndx:=-1;
|
||||||
for i:=nsects-1 downto 1 do
|
for i:=nsects-1 downto 1 do
|
||||||
begin
|
begin
|
||||||
if isdyn and (shdrs[i].sh_type=SHT_DYNAMIC) then
|
if (shdrs[i].sh_type<>symsectypes[dynobj]) then
|
||||||
dynndx:=i;
|
|
||||||
if (shdrs[i].sh_type<>symsectypes[isdyn]) then
|
|
||||||
continue;
|
continue;
|
||||||
if (shdrs[i].sh_entsize<>sizeof(TElfSymbol)) then
|
if (shdrs[i].sh_entsize<>sizeof(TElfSymbol)) then
|
||||||
InternalError(2012060213);
|
InternalError(2012060213);
|
||||||
@ -1913,16 +1937,71 @@ implementation
|
|||||||
localsyms:=shdrs[i].sh_info;
|
localsyms:=shdrs[i].sh_info;
|
||||||
FLoaded[i]:=True;
|
FLoaded[i]:=True;
|
||||||
FLoaded[strndx]:=True;
|
FLoaded[strndx]:=True;
|
||||||
|
symtabndx:=i;
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if isdyn then
|
if dynobj then
|
||||||
begin
|
begin
|
||||||
|
{ Locate .dynamic and version sections. Expect a single one of a kind. }
|
||||||
|
dynndx:=0;
|
||||||
|
versymndx:=0;
|
||||||
|
verdefndx:=0;
|
||||||
|
verneedndx:=0;
|
||||||
|
for i:=nsects-1 downto 0 do
|
||||||
|
begin
|
||||||
|
case shdrs[i].sh_type of
|
||||||
|
SHT_DYNAMIC:
|
||||||
|
begin
|
||||||
|
if dynndx<>0 then
|
||||||
|
InternalError(2012102001);
|
||||||
|
dynndx:=i;
|
||||||
|
if (shdrs[dynndx].sh_link<>strndx) then
|
||||||
|
InternalError(2012071402);
|
||||||
|
LoadDynamic(shdrs[dynndx],objdata);
|
||||||
|
end;
|
||||||
|
|
||||||
|
SHT_GNU_versym:
|
||||||
|
begin
|
||||||
|
if versymndx<>0 then
|
||||||
|
InternalError(2012102002);
|
||||||
|
versymndx:=i;
|
||||||
|
if shdrs[i].sh_entsize<>sizeof(word) then
|
||||||
|
InternalError(2012102003);
|
||||||
|
if shdrs[i].sh_link<>symtabndx then
|
||||||
|
InternalError(2012102004);
|
||||||
|
if shdrs[i].sh_size<>syms*sizeof(word) then
|
||||||
|
InternalError(2012102005);
|
||||||
|
GetMem(symversions,shdrs[i].sh_size);
|
||||||
|
FReader.seek(shdrs[i].sh_offset);
|
||||||
|
FReader.read(symversions^,shdrs[i].sh_size);
|
||||||
|
if source_info.endian<>target_info.endian then
|
||||||
|
for j:=0 to syms-1 do
|
||||||
|
SwapEndian(symversions[j]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
SHT_GNU_verdef:
|
||||||
|
begin
|
||||||
|
if verdefndx<>0 then
|
||||||
|
InternalError(2012102006);
|
||||||
|
verdefndx:=i;
|
||||||
|
//sh_link->.dynstr
|
||||||
|
//sh_info->.hash
|
||||||
|
end;
|
||||||
|
|
||||||
|
SHT_GNU_verneed:
|
||||||
|
begin
|
||||||
|
if verneedndx<>0 then
|
||||||
|
InternalError(2012102007);
|
||||||
|
verneedndx:=i;
|
||||||
|
//sh_link->.dynstr
|
||||||
|
//sh_info->hash
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
if dynndx=0 then
|
if dynndx=0 then
|
||||||
InternalError(2012071401);
|
InternalError(2012071401);
|
||||||
if (shdrs[dynndx].sh_link<>strndx) then
|
|
||||||
InternalError(2012071402);
|
|
||||||
LoadDynamic(shdrs[dynndx],objdata);
|
|
||||||
|
|
||||||
{ for DSO, we aren't interested in actual sections, but need to a dummy one
|
{ for DSO, we aren't interested in actual sections, but need to a dummy one
|
||||||
to maintain integrity. }
|
to maintain integrity. }
|
||||||
@ -2270,10 +2349,26 @@ implementation
|
|||||||
|
|
||||||
|
|
||||||
procedure TElfExeOutput.Load_DynamicObject(objdata:TObjData);
|
procedure TElfExeOutput.Load_DynamicObject(objdata:TObjData);
|
||||||
|
var
|
||||||
|
i: longint;
|
||||||
|
exesym: TExeSymbol;
|
||||||
|
objsym: TObjSymbol;
|
||||||
begin
|
begin
|
||||||
Comment(v_debug,'Dynamic object: '+objdata.name);
|
Comment(v_debug,'Dynamic object: '+objdata.name);
|
||||||
if neededlist.Find(objdata.name)=nil then
|
if neededlist.Find(objdata.name)=nil then
|
||||||
neededlist.Add(objdata.name,objdata);
|
neededlist.Add(objdata.name,objdata);
|
||||||
|
for i:=0 to UnresolvedExeSymbols.Count-1 do
|
||||||
|
begin
|
||||||
|
exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
|
||||||
|
if exesym.State<>symstate_undefined then
|
||||||
|
continue;
|
||||||
|
objsym:=TObjSymbol(objdata.ObjSymbolList.Find(exesym.name));
|
||||||
|
if assigned(objsym) then
|
||||||
|
begin
|
||||||
|
exesym.State:=symstate_defined;
|
||||||
|
exesym.dynindex:=dynsymlist.Add(exesym)+1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -2339,6 +2434,24 @@ implementation
|
|||||||
objsym:TObjSymbol;
|
objsym:TObjSymbol;
|
||||||
objsec: TObjSection;
|
objsec: TObjSection;
|
||||||
begin
|
begin
|
||||||
|
{ Unused section removal changes state of referenced exesymbols
|
||||||
|
to symstate_dynamic. Remaining ones can be removed. }
|
||||||
|
for i:=0 to dynsymlist.count-1 do
|
||||||
|
begin
|
||||||
|
exesym:=TExeSymbol(dynsymlist[i]);
|
||||||
|
if assigned(exesym.ObjSymbol.ObjSection) then // an exported symbol
|
||||||
|
continue;
|
||||||
|
if exesym.state<>symstate_dynamic then
|
||||||
|
begin
|
||||||
|
dynsymlist[i]:=nil;
|
||||||
|
exesym.dynindex:=0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
dynsymlist.Pack;
|
||||||
|
{ reindex }
|
||||||
|
for i:=0 to dynsymlist.count-1 do
|
||||||
|
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. }
|
||||||
for i:=0 to UnresolvedExeSymbols.Count-1 do
|
for i:=0 to UnresolvedExeSymbols.Count-1 do
|
||||||
@ -2360,9 +2473,11 @@ implementation
|
|||||||
PrepareGOT;
|
PrepareGOT;
|
||||||
|
|
||||||
{ Write required PLT entries }
|
{ Write required PLT entries }
|
||||||
for i:=0 to UnresolvedExeSymbols.Count-1 do
|
for i:=0 to dynsymlist.Count-1 do
|
||||||
begin
|
begin
|
||||||
exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
|
exesym:=TExeSymbol(dynsymlist[i]);
|
||||||
|
if assigned(exesym.ObjSymbol.objsection) then // an exported symbol
|
||||||
|
continue;
|
||||||
|
|
||||||
{ if there's no PLT references to symbol, then PLT entry isn't needed }
|
{ if there's no PLT references to symbol, then PLT entry isn't needed }
|
||||||
{ !! Does not work correctly yet !! }
|
{ !! Does not work correctly yet !! }
|
||||||
@ -2961,9 +3076,15 @@ implementation
|
|||||||
InternalError(2012071801);
|
InternalError(2012071801);
|
||||||
until exportlist.empty;
|
until exportlist.empty;
|
||||||
|
|
||||||
if not (cs_link_staticflag in current_settings.globalswitches) then
|
{ Mark unresolved weak symbols as defined, they will become dynamic further on.
|
||||||
for i:=0 to UnresolvedExeSymbols.Count-1 do
|
If compiling a .so, make all symbols dynamic, since shared library may reference
|
||||||
TExeSymbol(UnresolvedExeSymbols[i]).state:=symstate_defined;
|
symbols from executable which does not participate in linking. }
|
||||||
|
for i:=0 to UnresolvedExeSymbols.Count-1 do
|
||||||
|
begin
|
||||||
|
sym:=TExeSymbol(UnresolvedExeSymbols[i]);
|
||||||
|
if (sym.objsymbol.bind=AB_WEAK_EXTERNAL) or IsSharedLibrary then
|
||||||
|
sym.state:=symstate_defined;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user