* 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:
sergei 2012-06-20 14:16:48 +00:00
parent 98fffb7981
commit bd7ebdce18
2 changed files with 71 additions and 82 deletions

View File

@ -173,10 +173,12 @@ interface
TObjRelocation = class TObjRelocation = class
DataOffset, 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; symbol : TObjSymbol;
objsection : TObjSection; { only used if symbol=nil } objsection : TObjSection; { only used if symbol=nil }
typ : TObjRelocationType; typ : TObjRelocationType;
size : byte;
constructor CreateSymbol(ADataOffset:aword;s:TObjSymbol;Atyp:TObjRelocationType); constructor CreateSymbol(ADataOffset:aword;s:TObjSymbol;Atyp:TObjRelocationType);
constructor CreateSymbolSize(ADataOffset:aword;s:TObjSymbol;Aorgsize:aword;Atyp:TObjRelocationType); constructor CreateSymbolSize(ADataOffset:aword;s:TObjSymbol;Aorgsize:aword;Atyp:TObjRelocationType);
constructor CreateSection(ADataOffset:aword;aobjsec:TObjSection;Atyp:TObjRelocationType); constructor CreateSection(ADataOffset:aword;aobjsec:TObjSection;Atyp:TObjRelocationType);

View File

@ -152,8 +152,22 @@ implementation
{ 32 bit signed PC relative offset to GOT entry for IE symbol } { 32 bit signed PC relative offset to GOT entry for IE symbol }
R_X86_64_GOTTPOFF = 22; R_X86_64_GOTTPOFF = 22;
R_X86_64_TPOFF32 = 23; { Offset in initial TLS block } 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_PC64 = 24; { PC relative 64-bit signed }
R_X86_64_GNU_VTENTRY = 25; { GNU extension to record C++ vtable member usage } 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} {$endif x86_64}
{ ELFHeader.file_class } { ELFHeader.file_class }
@ -331,6 +345,7 @@ implementation
TElf32reloc=packed record TElf32reloc=packed record
address : longint; address : longint;
info : longint; { bit 0-7: type, 8-31: symbol } info : longint; { bit 0-7: type, 8-31: symbol }
addend : longint;
end; end;
TElf32symbol=packed record TElf32symbol=packed record
st_name : longint; st_name : longint;
@ -433,6 +448,13 @@ implementation
telfdyn = telf32dyn; telfdyn = telf32dyn;
{$endif cpu64bitaddr} {$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); procedure MayBeSwapHeader(var h : telf32header);
begin begin
@ -583,6 +605,7 @@ implementation
begin begin
address:=swapendian(address); address:=swapendian(address);
info:=swapendian(info); info:=swapendian(info);
addend:=swapendian(addend);
end; end;
end; end;
@ -888,24 +911,18 @@ implementation
procedure TElfObjData.writereloc(data:aint;len:aword;p:TObjSymbol;reltype:TObjRelocationType); procedure TElfObjData.writereloc(data:aint;len:aword;p:TObjSymbol;reltype:TObjRelocationType);
var var
symaddr : aint; symaddr : aint;
objreloc: TObjRelocation;
begin begin
if CurrObjSec=nil then if CurrObjSec=nil then
internalerror(200403292); internalerror(200403292);
{$ifdef userodata} objreloc:=nil;
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;
if assigned(p) then if assigned(p) then
begin begin
{ real address of the symbol } { real address of the symbol }
symaddr:=p.address; symaddr:=p.address;
{ Local ObjSymbols can be resolved already or need a section reloc } { Local ObjSymbols can be resolved already or need a section reloc }
if (p.bind=AB_LOCAL) and 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 begin
{ For a reltype relocation in the same section the { For a reltype relocation in the same section the
value can be calculated } value can be calculated }
@ -914,19 +931,28 @@ implementation
inc(data,symaddr-len-CurrObjSec.Size) inc(data,symaddr-len-CurrObjSec.Size)
else else
begin begin
CurrObjSec.addsectionreloc(CurrObjSec.Size,p.objsection,reltype); objreloc:=TObjRelocation.CreateSection(CurrObjSec.Size,p.objsection,reltype);
CurrObjSec.ObjRelocations.Add(objreloc);
inc(data,symaddr); inc(data,symaddr);
end; end;
end end
else else
begin begin
CurrObjSec.addsymreloc(CurrObjSec.Size,p,reltype); objreloc:=TObjRelocation.CreateSymbol(CurrObjSec.Size,p,reltype);
{$ifndef x86_64} CurrObjSec.ObjRelocations.Add(objreloc);
if (reltype=RELOC_RELATIVE) or (reltype=RELOC_PLT32) then
dec(data,len);
{$endif x86_64}
end; end;
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); CurrObjSec.write(data,len);
end; end;
@ -1051,35 +1077,22 @@ implementation
objreloc : TObjRelocation; objreloc : TObjRelocation;
relsym, relsym,
reltyp : longint; reltyp : longint;
relocsect : TObjSection; relocsect : TElfObjSection;
{$ifdef x86_64}
tmp: aint;
asize: longint;
{$endif x86_64}
begin begin
with data do with data do
begin 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 } { create the reloc section }
{$ifdef i386} if relocs_use_addend then
relocsect:=TElfObjSection.create_ext(data,'.rel'+s.name,SHT_REL,0,symtabsect.secshidx,s.secshidx,4,sizeof(TElfReloc)); relocsect:=TElfObjSection.create_ext(data,'.rela'+s.name,SHT_RELA,0,symtabsect.secshidx,s.secshidx,4,3*sizeof(pint))
{$else i386} else
relocsect:=TElfObjSection.create_ext(data,'.rela'+s.name,SHT_RELA,0,symtabsect.secshidx,s.secshidx,4,sizeof(TElfReloc)); relocsect:=TElfObjSection.create_ext(data,'.rel'+s.name,SHT_REL,0,symtabsect.secshidx,s.secshidx,4,2*sizeof(pint));
{$endif i386}
{ add the relocations } { add the relocations }
for i:=0 to s.Objrelocations.count-1 do for i:=0 to s.Objrelocations.count-1 do
begin begin
objreloc:=TObjRelocation(s.Objrelocations[i]); objreloc:=TObjRelocation(s.Objrelocations[i]);
fillchar(rel,sizeof(rel),0); fillchar(rel,sizeof(rel),0);
rel.address:=objreloc.dataoffset; rel.address:=objreloc.dataoffset;
rel.addend:=objreloc.orgsize;
{ when things settle down, we can create processor specific { when things settle down, we can create processor specific
derived classes } derived classes }
@ -1094,67 +1107,40 @@ implementation
RELOC_GOTPC : RELOC_GOTPC :
reltyp:=R_386_GOTPC; reltyp:=R_386_GOTPC;
RELOC_PLT32 : RELOC_PLT32 :
begin reltyp:=R_386_PLT32;
reltyp:=R_386_PLT32;
end;
{$endif i386} {$endif i386}
{$ifdef sparc} {$ifdef sparc}
RELOC_ABSOLUTE : RELOC_ABSOLUTE :
reltyp:=R_SPARC_32; reltyp:=R_SPARC_32;
{$endif sparc} {$endif sparc}
{$ifdef x86_64} {$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 : RELOC_RELATIVE :
begin if objreloc.size=8 then
reltyp:=R_X86_64_PC32; reltyp:=R_X86_64_PC64
{ length of the relocated location is handled here } else if objreloc.size=4 then
rel.addend:=-4; reltyp:=R_X86_64_PC32
end; else
InternalError(2012061900);
RELOC_ABSOLUTE : 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 : RELOC_ABSOLUTE32 :
reltyp:=R_X86_64_32S; reltyp:=R_X86_64_32S;
RELOC_RVA :
reltyp:=R_X86_64_32;
RELOC_GOTPCREL : RELOC_GOTPCREL :
begin reltyp:=R_X86_64_GOTPCREL;
reltyp:=R_X86_64_GOTPCREL;
{ length of the relocated location is handled here }
rel.addend:=-4;
end;
RELOC_PLT32 : RELOC_PLT32 :
begin reltyp:=R_X86_64_PLT32;
reltyp:=R_X86_64_PLT32;
{ length of the relocated location is handled here }
rel.addend:=-4;
end;
{$endif x86_64} {$endif x86_64}
else else
internalerror(200602261); internalerror(200602261);
end; 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 } { Symbol }
if assigned(objreloc.symbol) then if assigned(objreloc.symbol) then
begin begin
@ -1178,8 +1164,9 @@ implementation
rel.info:=(relsym shl 8) or reltyp; rel.info:=(relsym shl 8) or reltyp;
{$endif cpu64bitaddr} {$endif cpu64bitaddr}
{ write reloc } { write reloc }
{ ElfXX_Rel is essentially ElfXX_Rela without the addend field. }
MaybeSwapElfReloc(rel); MaybeSwapElfReloc(rel);
relocsect.write(rel,sizeof(rel)); relocsect.write(rel,relocsect.shentsize);
end; end;
end; end;
end; end;