mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-14 09:29:26 +02:00
x86_64 internal ELF linker:
* Split generation of regular and TLSIE GOT entries. Although code for both is similar to some extent, mixing them in a single method turns it into spaghetti. * Several fixes to content and dynamic relocations of TLSIE entries. git-svn-id: trunk@25180 -
This commit is contained in:
parent
db0585f388
commit
11b72b5515
@ -35,7 +35,8 @@ implementation
|
|||||||
type
|
type
|
||||||
TElfExeOutputx86_64=class(TElfExeOutput)
|
TElfExeOutputx86_64=class(TElfExeOutput)
|
||||||
private
|
private
|
||||||
procedure MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
|
procedure MaybeWriteGOTEntry(relocval:aint;objsym:TObjSymbol);
|
||||||
|
procedure MaybeWriteTLSIEGotEntry(relocval:aint;objsym:TObjSymbol);
|
||||||
protected
|
protected
|
||||||
procedure WriteFirstPLTEntry;override;
|
procedure WriteFirstPLTEntry;override;
|
||||||
procedure WritePLTEntry(exesym:TExeSymbol);override;
|
procedure WritePLTEntry(exesym:TExeSymbol);override;
|
||||||
@ -260,7 +261,7 @@ implementation
|
|||||||
ReportNonDSOReloc(reltyp,objsec,objreloc);
|
ReportNonDSOReloc(reltyp,objsec,objreloc);
|
||||||
|
|
||||||
{ R_X86_64_32 is processed by rtld, but binutils accept it in data sections only.
|
{ R_X86_64_32 is processed by rtld, but binutils accept it in data sections only.
|
||||||
Relocating the against local symbols is tricky: changing into RELATIVE is not possible,
|
Relocating against local symbols is tricky: changing into RELATIVE is not possible,
|
||||||
so it is changed into relocation against section symbol. This requires adding
|
so it is changed into relocation against section symbol. This requires adding
|
||||||
the appropriate section symbol to dynamic symtable. BFD also has some obscure logic
|
the appropriate section symbol to dynamic symtable. BFD also has some obscure logic
|
||||||
behind, e.g. it uses .text section for symbols from .data section.
|
behind, e.g. it uses .text section for symbols from .data section.
|
||||||
@ -320,7 +321,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TElfExeOutputx86_64.MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
|
procedure TElfExeOutputx86_64.MaybeWriteGOTEntry(relocval:aint;objsym:TObjSymbol);
|
||||||
var
|
var
|
||||||
gotoff,tmp:aword;
|
gotoff,tmp:aword;
|
||||||
begin
|
begin
|
||||||
@ -334,18 +335,43 @@ implementation
|
|||||||
begin
|
begin
|
||||||
gotobjsec.write(relocval,sizeof(pint));
|
gotobjsec.write(relocval,sizeof(pint));
|
||||||
|
|
||||||
|
tmp:=gotobjsec.mempos+gotoff-sizeof(pint);
|
||||||
|
if (objsym.exesymbol.dynindex>0) then
|
||||||
|
dynreloclist.Add(TObjRelocation.CreateRaw(tmp,objsym,R_X86_64_GLOB_DAT))
|
||||||
|
else
|
||||||
|
if IsSharedLibrary then
|
||||||
|
WriteDynRelocEntry(tmp,R_X86_64_RELATIVE,0,relocval);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TElfExeOutputx86_64.MaybeWriteTLSIEGotEntry(relocval:aint;objsym:TObjSymbol);
|
||||||
|
var
|
||||||
|
gotoff,tmp: aword;
|
||||||
|
objrel: TObjRelocation;
|
||||||
|
begin
|
||||||
|
gotoff:=objsym.exesymbol.gotoffset;
|
||||||
|
if gotoff=0 then
|
||||||
|
InternalError(2012060903);
|
||||||
|
|
||||||
|
if gotoff=gotobjsec.Data.size+sizeof(pint) then
|
||||||
|
begin
|
||||||
tmp:=gotobjsec.mempos+gotoff-sizeof(pint);
|
tmp:=gotobjsec.mempos+gotoff-sizeof(pint);
|
||||||
if (objsym.exesymbol.dynindex>0) then
|
if (objsym.exesymbol.dynindex>0) then
|
||||||
begin
|
begin
|
||||||
if (reltyp=R_X86_64_GOTTPOFF) then
|
gotobjsec.writezeros(sizeof(pint));
|
||||||
if IsSharedLibrary then
|
dynreloclist.Add(TObjRelocation.CreateRaw(tmp,objsym,R_X86_64_TPOFF64));
|
||||||
dynreloclist.Add(TObjRelocation.CreateRaw(tmp,objsym,R_X86_64_TPOFF64)) // probably incorrect
|
|
||||||
else
|
|
||||||
else
|
|
||||||
dynreloclist.Add(TObjRelocation.CreateRaw(tmp,objsym,R_X86_64_GLOB_DAT));
|
|
||||||
end
|
end
|
||||||
else if IsSharedLibrary then
|
else
|
||||||
WriteDynRelocEntry(tmp,R_X86_64_RELATIVE,0,relocval);
|
begin
|
||||||
|
gotobjsec.write(relocval,sizeof(pint));
|
||||||
|
if IsSharedLibrary then
|
||||||
|
begin
|
||||||
|
objrel:=TObjRelocation.CreateRaw(tmp,nil,R_X86_64_TPOFF64);
|
||||||
|
objrel.orgsize:=relocval;
|
||||||
|
dynreloclist.Add(objrel);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -434,8 +460,8 @@ implementation
|
|||||||
//R_X86_64_DTPOFF64 is possible in data??
|
//R_X86_64_DTPOFF64 is possible in data??
|
||||||
R_X86_64_DTPOFF32:
|
R_X86_64_DTPOFF32:
|
||||||
begin
|
begin
|
||||||
{ In executable it behaves as TPOFF32, but data expressions
|
{ In executable it behaves as TPOFF32 (i.e. generates negative offset),
|
||||||
like ".long foo@dtpoff" resolve to positive offset }
|
but data expressions like ".long foo@dtpoff" resolve to positive offset }
|
||||||
if IsSharedLibrary or not (oso_executable in objsec.SecOptions) then
|
if IsSharedLibrary or not (oso_executable in objsec.SecOptions) then
|
||||||
address:=address+relocval-tlsseg.MemPos
|
address:=address+relocval-tlsseg.MemPos
|
||||||
else
|
else
|
||||||
@ -446,14 +472,24 @@ implementation
|
|||||||
R_X86_64_TPOFF64:
|
R_X86_64_TPOFF64:
|
||||||
address:=address+relocval-(tlsseg.MemPos+tlsseg.MemSize);
|
address:=address+relocval-(tlsseg.MemPos+tlsseg.MemSize);
|
||||||
|
|
||||||
R_X86_64_GOTTPOFF,
|
R_X86_64_GOTTPOFF:
|
||||||
|
begin
|
||||||
|
if IsSharedLibrary then
|
||||||
|
relocval:=relocval-tlsseg.MemPos
|
||||||
|
else
|
||||||
|
relocval:=relocval-(tlsseg.MemPos+tlsseg.MemSize);
|
||||||
|
|
||||||
|
MaybeWriteTLSIEGotEntry(relocval,objreloc.symbol);
|
||||||
|
|
||||||
|
{ resolves to PC-relative offset to GOT slot }
|
||||||
|
relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint);
|
||||||
|
address:=address+relocval-PC;
|
||||||
|
end;
|
||||||
|
|
||||||
R_X86_64_GOTPCREL,
|
R_X86_64_GOTPCREL,
|
||||||
R_X86_64_GOTPCREL64:
|
R_X86_64_GOTPCREL64:
|
||||||
begin
|
begin
|
||||||
if (reltyp=R_X86_64_GOTTPOFF) then
|
MaybeWriteGOTEntry(relocval,objreloc.symbol);
|
||||||
relocval:=relocval-(tlsseg.MemPos+tlsseg.MemSize);
|
|
||||||
|
|
||||||
MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
|
|
||||||
|
|
||||||
{ resolves to PC-relative offset to GOT slot }
|
{ resolves to PC-relative offset to GOT slot }
|
||||||
relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint);
|
relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint);
|
||||||
@ -488,7 +524,7 @@ implementation
|
|||||||
R_X86_64_GOT32,
|
R_X86_64_GOT32,
|
||||||
R_X86_64_GOT64:
|
R_X86_64_GOT64:
|
||||||
begin
|
begin
|
||||||
MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
|
MaybeWriteGOTEntry(relocval,objreloc.symbol);
|
||||||
|
|
||||||
relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint)-gotsymbol.address;
|
relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint)-gotsymbol.address;
|
||||||
address:=address+relocval;
|
address:=address+relocval;
|
||||||
|
Loading…
Reference in New Issue
Block a user