Browse Source

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

sergei 13 years ago
parent
commit
bd7ebdce18
2 changed files with 71 additions and 82 deletions
  1. 3 1
      compiler/ogbase.pas
  2. 68 81
      compiler/ogelf.pas

+ 3 - 1
compiler/ogbase.pas

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

+ 68 - 81
compiler/ogelf.pas

@@ -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_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}
 {$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}
-        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
         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);
-{$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;
          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;
-{$ifdef x86_64}	
-        tmp: aint;
-        asize: longint;
-{$endif x86_64}	
+        relocsect : TElfObjSection;
       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}
-           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 }
            { 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;
-                   end;
+                   reltyp:=R_386_PLT32;
 {$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
-                     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 :
                  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;
-                     { length of the relocated location is handled here }
-                     rel.addend:=-4;
-                   end;
+                   reltyp:=R_X86_64_GOTPCREL;
                  RELOC_PLT32 :
                  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}
 {$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;