Explorar el Código

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 -

sergei hace 12 años
padre
commit
11b72b5515
Se han modificado 1 ficheros con 55 adiciones y 19 borrados
  1. 55 19
      compiler/x86_64/cpuelf.pas

+ 55 - 19
compiler/x86_64/cpuelf.pas

@@ -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
-                if IsSharedLibrary then
-                  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));
+              gotobjsec.writezeros(sizeof(pint));
+              dynreloclist.Add(TObjRelocation.CreateRaw(tmp,objsym,R_X86_64_TPOFF64));
             end
             end
-          else if IsSharedLibrary then
-            WriteDynRelocEntry(tmp,R_X86_64_RELATIVE,0,relocval);
+          else
+            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
-                    like ".long foo@dtpoff" resolve to positive offset }
+                  { In executable it behaves as TPOFF32 (i.e. generates negative 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_GOTPCREL,
-              R_X86_64_GOTPCREL64:
+              R_X86_64_GOTTPOFF:
                 begin
                 begin
-                  if (reltyp=R_X86_64_GOTTPOFF) then
+                  if IsSharedLibrary then
+                    relocval:=relocval-tlsseg.MemPos
+                  else
                     relocval:=relocval-(tlsseg.MemPos+tlsseg.MemSize);
                     relocval:=relocval-(tlsseg.MemPos+tlsseg.MemSize);
 
 
-                  MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
+                  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_GOTPCREL64:
+                begin
+                  MaybeWriteGOTEntry(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;