* 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
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);

View File

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