* 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:
sergei 2012-10-23 15:16:10 +00:00
parent f94ba86bb9
commit 6023f73e2a

View File

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