mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-19 20:59:42 +02:00
* ELF relocation cleanup/improvement:
+ Store size of relocation and explicit addend in TObjRelocation (reusing 'orgsize' field for the latter). This removes need for reading addends back from section data, addends are stored in full 64 bits and therefore not truncated. + Relocation style is now controlled by relocs_use_addend variable instead of $ifdef's. - Removed (never working) checks forbidding relocations of readonly sections. At the linking stage readonly sections *can* have relocations, executable stage is different matter to be handled elsewhere. - removed ugly hack with mapping 32-bit absolute relocations to RELOC_RVA. + support 64-bit relative relocations. * actualized list of x86_64 relocations. git-svn-id: trunk@21662 -
This commit is contained in:
parent
98fffb7981
commit
bd7ebdce18
@ -173,10 +173,12 @@ interface
|
||||
|
||||
TObjRelocation = class
|
||||
DataOffset,
|
||||
orgsize : aword; { original size of the symbol to Relocate, required for COFF }
|
||||
orgsize : aword; { COFF: original size of the symbol to relocate }
|
||||
{ ELF: explicit addend }
|
||||
symbol : TObjSymbol;
|
||||
objsection : TObjSection; { only used if symbol=nil }
|
||||
typ : TObjRelocationType;
|
||||
size : byte;
|
||||
constructor CreateSymbol(ADataOffset:aword;s:TObjSymbol;Atyp:TObjRelocationType);
|
||||
constructor CreateSymbolSize(ADataOffset:aword;s:TObjSymbol;Aorgsize:aword;Atyp:TObjRelocationType);
|
||||
constructor CreateSection(ADataOffset:aword;aobjsec:TObjSection;Atyp:TObjRelocationType);
|
||||
|
@ -152,8 +152,22 @@ implementation
|
||||
{ 32 bit signed PC relative offset to GOT entry for IE symbol }
|
||||
R_X86_64_GOTTPOFF = 22;
|
||||
R_X86_64_TPOFF32 = 23; { Offset in initial TLS block }
|
||||
R_X86_64_GNU_VTINHERIT = 24; { GNU extension to record C++ vtable hierarchy }
|
||||
R_X86_64_GNU_VTENTRY = 25; { GNU extension to record C++ vtable member usage }
|
||||
R_X86_64_PC64 = 24; { PC relative 64-bit signed }
|
||||
R_X86_64_GOTOFF64 = 25; { 64-bit offset from GOT base }
|
||||
R_X86_64_GOTPC32 = 26; { PC-relative offset GOT }
|
||||
R_X86_64_GOT64 = 27; { 64-bit GOT entry offset }
|
||||
R_X86_64_GOTPCREL64 = 28; { 64-bit PC relative offset to GOT entry }
|
||||
R_X86_64_GOTPC64 = 29; { 64-bit PC relative offset to GOT }
|
||||
R_X86_64_GOTPLT64 = 30; { Like GOT64, indicates that PLT entry needed }
|
||||
R_X86_64_PLTOFF64 = 31; { 64-bit GOT relative offset to PLT entry }
|
||||
R_X86_64_SIZE32 = 32;
|
||||
R_X86_64_SIZE64 = 33;
|
||||
R_X86_64_GOTPC32_TLSDESC = 34;
|
||||
R_X86_64_TLSDESC_CALL = 35;
|
||||
R_X86_64_TLSDESC = 36;
|
||||
R_X86_64_IRELATIVE = 37;
|
||||
R_X86_64_GNU_VTINHERIT = 250; { GNU extension to record C++ vtable hierarchy }
|
||||
R_X86_64_GNU_VTENTRY = 251; { GNU extension to record C++ vtable member usage }
|
||||
{$endif x86_64}
|
||||
|
||||
{ ELFHeader.file_class }
|
||||
@ -331,6 +345,7 @@ implementation
|
||||
TElf32reloc=packed record
|
||||
address : longint;
|
||||
info : longint; { bit 0-7: type, 8-31: symbol }
|
||||
addend : longint;
|
||||
end;
|
||||
TElf32symbol=packed record
|
||||
st_name : longint;
|
||||
@ -433,6 +448,13 @@ implementation
|
||||
telfdyn = telf32dyn;
|
||||
{$endif cpu64bitaddr}
|
||||
|
||||
{$ifdef x86_64}
|
||||
const
|
||||
relocs_use_addend:Boolean=True;
|
||||
{$else x86_64}
|
||||
const
|
||||
relocs_use_addend:Boolean=False;
|
||||
{$endif x86_64}
|
||||
|
||||
procedure MayBeSwapHeader(var h : telf32header);
|
||||
begin
|
||||
@ -583,6 +605,7 @@ implementation
|
||||
begin
|
||||
address:=swapendian(address);
|
||||
info:=swapendian(info);
|
||||
addend:=swapendian(addend);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -888,24 +911,18 @@ implementation
|
||||
procedure TElfObjData.writereloc(data:aint;len:aword;p:TObjSymbol;reltype:TObjRelocationType);
|
||||
var
|
||||
symaddr : aint;
|
||||
objreloc: TObjRelocation;
|
||||
begin
|
||||
if CurrObjSec=nil then
|
||||
internalerror(200403292);
|
||||
{$ifdef userodata}
|
||||
if CurrObjSec.sectype in [sec_rodata,sec_bss,sec_threadvar] then
|
||||
internalerror(200408252);
|
||||
{$endif userodata}
|
||||
{ Using RELOC_RVA to map 32-bit RELOC_ABSOLUTE to R_X86_64_32
|
||||
(RELOC_ABSOLUTE maps to R_X86_64_32S) }
|
||||
if (reltype=RELOC_ABSOLUTE) and (len<>sizeof(pint)) then
|
||||
reltype:=RELOC_RVA;
|
||||
objreloc:=nil;
|
||||
if assigned(p) then
|
||||
begin
|
||||
{ real address of the symbol }
|
||||
symaddr:=p.address;
|
||||
{ Local ObjSymbols can be resolved already or need a section reloc }
|
||||
if (p.bind=AB_LOCAL) and
|
||||
(reltype in [RELOC_RELATIVE,RELOC_ABSOLUTE{$ifdef x86_64},RELOC_ABSOLUTE32,RELOC_RVA{$endif x86_64}]) then
|
||||
(reltype in [RELOC_RELATIVE,RELOC_ABSOLUTE{$ifdef x86_64},RELOC_ABSOLUTE32{$endif x86_64}]) then
|
||||
begin
|
||||
{ For a reltype relocation in the same section the
|
||||
value can be calculated }
|
||||
@ -914,19 +931,28 @@ implementation
|
||||
inc(data,symaddr-len-CurrObjSec.Size)
|
||||
else
|
||||
begin
|
||||
CurrObjSec.addsectionreloc(CurrObjSec.Size,p.objsection,reltype);
|
||||
objreloc:=TObjRelocation.CreateSection(CurrObjSec.Size,p.objsection,reltype);
|
||||
CurrObjSec.ObjRelocations.Add(objreloc);
|
||||
inc(data,symaddr);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
CurrObjSec.addsymreloc(CurrObjSec.Size,p,reltype);
|
||||
{$ifndef x86_64}
|
||||
if (reltype=RELOC_RELATIVE) or (reltype=RELOC_PLT32) then
|
||||
dec(data,len);
|
||||
{$endif x86_64}
|
||||
objreloc:=TObjRelocation.CreateSymbol(CurrObjSec.Size,p,reltype);
|
||||
CurrObjSec.ObjRelocations.Add(objreloc);
|
||||
end;
|
||||
end;
|
||||
if assigned(objreloc) then
|
||||
begin
|
||||
objreloc.size:=len;
|
||||
if reltype in [RELOC_RELATIVE,RELOC_PLT32{$ifdef x86_64},RELOC_GOTPCREL{$endif}] then
|
||||
dec(data,len);
|
||||
if relocs_use_addend then
|
||||
begin
|
||||
objreloc.orgsize:=data;
|
||||
data:=0;
|
||||
end;
|
||||
end;
|
||||
CurrObjSec.write(data,len);
|
||||
end;
|
||||
|
||||
@ -1051,35 +1077,22 @@ implementation
|
||||
objreloc : TObjRelocation;
|
||||
relsym,
|
||||
reltyp : longint;
|
||||
relocsect : TObjSection;
|
||||
{$ifdef x86_64}
|
||||
tmp: aint;
|
||||
asize: longint;
|
||||
{$endif x86_64}
|
||||
relocsect : TElfObjSection;
|
||||
begin
|
||||
with data do
|
||||
begin
|
||||
{$ifdef userodata}
|
||||
{ rodata can't have relocations }
|
||||
if s.sectype=sec_rodata then
|
||||
begin
|
||||
if assigned(s.relocations.first) then
|
||||
internalerror(200408251);
|
||||
exit;
|
||||
end;
|
||||
{$endif userodata}
|
||||
{ create the reloc section }
|
||||
{$ifdef i386}
|
||||
relocsect:=TElfObjSection.create_ext(data,'.rel'+s.name,SHT_REL,0,symtabsect.secshidx,s.secshidx,4,sizeof(TElfReloc));
|
||||
{$else i386}
|
||||
relocsect:=TElfObjSection.create_ext(data,'.rela'+s.name,SHT_RELA,0,symtabsect.secshidx,s.secshidx,4,sizeof(TElfReloc));
|
||||
{$endif i386}
|
||||
if relocs_use_addend then
|
||||
relocsect:=TElfObjSection.create_ext(data,'.rela'+s.name,SHT_RELA,0,symtabsect.secshidx,s.secshidx,4,3*sizeof(pint))
|
||||
else
|
||||
relocsect:=TElfObjSection.create_ext(data,'.rel'+s.name,SHT_REL,0,symtabsect.secshidx,s.secshidx,4,2*sizeof(pint));
|
||||
{ add the relocations }
|
||||
for i:=0 to s.Objrelocations.count-1 do
|
||||
begin
|
||||
objreloc:=TObjRelocation(s.Objrelocations[i]);
|
||||
fillchar(rel,sizeof(rel),0);
|
||||
rel.address:=objreloc.dataoffset;
|
||||
rel.addend:=objreloc.orgsize;
|
||||
|
||||
{ when things settle down, we can create processor specific
|
||||
derived classes }
|
||||
@ -1094,67 +1107,40 @@ implementation
|
||||
RELOC_GOTPC :
|
||||
reltyp:=R_386_GOTPC;
|
||||
RELOC_PLT32 :
|
||||
begin
|
||||
reltyp:=R_386_PLT32;
|
||||
end;
|
||||
reltyp:=R_386_PLT32;
|
||||
{$endif i386}
|
||||
{$ifdef sparc}
|
||||
RELOC_ABSOLUTE :
|
||||
reltyp:=R_SPARC_32;
|
||||
{$endif sparc}
|
||||
{$ifdef x86_64}
|
||||
{ Note: 8 and 16-bit relocations are known to be non-conformant with
|
||||
AMD64 ABI, so they aren't handled. }
|
||||
RELOC_RELATIVE :
|
||||
begin
|
||||
reltyp:=R_X86_64_PC32;
|
||||
{ length of the relocated location is handled here }
|
||||
rel.addend:=-4;
|
||||
end;
|
||||
if objreloc.size=8 then
|
||||
reltyp:=R_X86_64_PC64
|
||||
else if objreloc.size=4 then
|
||||
reltyp:=R_X86_64_PC32
|
||||
else
|
||||
InternalError(2012061900);
|
||||
RELOC_ABSOLUTE :
|
||||
reltyp:=R_X86_64_64;
|
||||
if objreloc.size=8 then
|
||||
reltyp:=R_X86_64_64
|
||||
else if objreloc.size=4 then
|
||||
reltyp:=R_X86_64_32
|
||||
else
|
||||
InternalError(2012061901);
|
||||
RELOC_ABSOLUTE32 :
|
||||
reltyp:=R_X86_64_32S;
|
||||
RELOC_RVA :
|
||||
reltyp:=R_X86_64_32;
|
||||
RELOC_GOTPCREL :
|
||||
begin
|
||||
reltyp:=R_X86_64_GOTPCREL;
|
||||
{ length of the relocated location is handled here }
|
||||
rel.addend:=-4;
|
||||
end;
|
||||
reltyp:=R_X86_64_GOTPCREL;
|
||||
RELOC_PLT32 :
|
||||
begin
|
||||
reltyp:=R_X86_64_PLT32;
|
||||
{ length of the relocated location is handled here }
|
||||
rel.addend:=-4;
|
||||
end;
|
||||
reltyp:=R_X86_64_PLT32;
|
||||
{$endif x86_64}
|
||||
else
|
||||
internalerror(200602261);
|
||||
end;
|
||||
|
||||
{ This handles ELF 'rela'-styled relocations, which are currently used only for x86_64,
|
||||
but can be used other targets, too. }
|
||||
{$ifdef x86_64}
|
||||
s.Data.Seek(objreloc.dataoffset);
|
||||
if objreloc.typ=RELOC_ABSOLUTE then
|
||||
begin
|
||||
asize:=8;
|
||||
s.Data.Read(tmp,8);
|
||||
rel.addend:=rel.addend+tmp;
|
||||
end
|
||||
else
|
||||
begin
|
||||
asize:=4;
|
||||
s.Data.Read(tmp,4);
|
||||
rel.addend:=rel.addend+longint(tmp);
|
||||
end;
|
||||
|
||||
{ and zero the data member out }
|
||||
tmp:=0;
|
||||
s.Data.Seek(objreloc.dataoffset);
|
||||
s.Data.Write(tmp,asize);
|
||||
{$endif}
|
||||
|
||||
{ Symbol }
|
||||
if assigned(objreloc.symbol) then
|
||||
begin
|
||||
@ -1178,8 +1164,9 @@ implementation
|
||||
rel.info:=(relsym shl 8) or reltyp;
|
||||
{$endif cpu64bitaddr}
|
||||
{ write reloc }
|
||||
{ ElfXX_Rel is essentially ElfXX_Rela without the addend field. }
|
||||
MaybeSwapElfReloc(rel);
|
||||
relocsect.write(rel,sizeof(rel));
|
||||
relocsect.write(rel,relocsect.shentsize);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user