Browse Source

+ support for tlsm_general on i386-linux

git-svn-id: trunk@40281 -
florian 6 years ago
parent
commit
72416edcc4

+ 1 - 1
compiler/i386/aoptcpu.pas

@@ -399,7 +399,7 @@ begin
                       begin
                       begin
                         if (base = NR_NO) and
                         if (base = NR_NO) and
                            (index <> NR_NO) and
                            (index <> NR_NO) and
-                           (scalefactor in [0,1]) then
+                           (scalefactor in [0,1]) and (refaddr<>addr_tlsgd) then
                           begin
                           begin
                             base := index;
                             base := index;
                             index := NR_NO
                             index := NR_NO

+ 8 - 1
compiler/i386/cpupi.pas

@@ -95,11 +95,18 @@ unit cpupi;
           para_stack_size := 0;
           para_stack_size := 0;
       end;
       end;
 
 
+
     procedure tcpuprocinfo.allocate_got_register(list: tasmlist);
     procedure tcpuprocinfo.allocate_got_register(list: tasmlist);
       begin
       begin
         if (cs_create_pic in current_settings.moduleswitches) then
         if (cs_create_pic in current_settings.moduleswitches) then
           begin
           begin
-            got := cg.getaddressregister(list);
+            if pi_uses_threadvar in flags then
+              begin
+                cg.getcpuregister(list,NR_EBX);
+                got := NR_EBX;
+              end
+            else
+              got := cg.getaddressregister(list);
           end;
           end;
       end;
       end;
 
 

+ 4 - 1
compiler/x86/aasmcpu.pas

@@ -1901,7 +1901,10 @@ implementation
             { Switching index to base position gives shorter assembler instructions.
             { Switching index to base position gives shorter assembler instructions.
               Converting index*2 to base+index also gives shorter instructions. }
               Converting index*2 to base+index also gives shorter instructions. }
             if (ref.base=NR_NO) and (ref.index<>NR_NO) and (ref.scalefactor<=2) and
             if (ref.base=NR_NO) and (ref.index<>NR_NO) and (ref.scalefactor<=2) and
-               (ss_equals_ds or (ref.segment<>NR_NO) or (ref.index<>NR_EBP)) then
+               (ss_equals_ds or (ref.segment<>NR_NO) or (ref.index<>NR_EBP))
+               { do not mess with tls references, they have the (,reg,1) format on purpose
+                 else the linker cannot resolve/replace them }
+               {$ifdef i386} and (ref.refaddr<>addr_tlsgd) {$endif i386} then
               begin
               begin
                 ref.base:=ref.index;
                 ref.base:=ref.index;
                 if ref.scalefactor=2 then
                 if ref.scalefactor=2 then

+ 3 - 1
compiler/x86/agx86att.pas

@@ -182,6 +182,8 @@ interface
 {$ifdef i386}
 {$ifdef i386}
              addr_ntpoff:
              addr_ntpoff:
                owner.writer.AsmWrite('@ntpoff');
                owner.writer.AsmWrite('@ntpoff');
+             addr_tlsgd:
+               owner.writer.AsmWrite('@tlsgd');
 {$endif i386}
 {$endif i386}
            end;
            end;
 
 
@@ -229,7 +231,7 @@ interface
             else
             else
               owner.writer.AsmWrite(gas_regname(o.reg));
               owner.writer.AsmWrite(gas_regname(o.reg));
           top_ref :
           top_ref :
-            if o.ref^.refaddr in [addr_no,addr_pic,addr_pic_no_got{$ifdef i386},addr_ntpoff{$endif i386}] then
+            if o.ref^.refaddr in [addr_no,addr_pic,addr_pic_no_got{$ifdef i386},addr_ntpoff,addr_tlsgd{$endif i386}] then
               WriteReference(o.ref^)
               WriteReference(o.ref^)
             else
             else
               begin
               begin

+ 24 - 4
compiler/x86/nx86ld.pas

@@ -40,10 +40,11 @@ implementation
     uses
     uses
       globals,
       globals,
       cutils,verbose,systems,
       cutils,verbose,systems,
-      aasmbase,aasmtai,aasmdata,
+      aasmbase,aasmtai,aasmdata,aasmcpu,
       cgutils,cgobj,
       cgutils,cgobj,
       symconst,symdef,symtable,
       symconst,symdef,symtable,
-      cgbase,cpubase,parabase,paramgr;
+      cgbase,cpubase,parabase,paramgr,
+      procinfo;
 
 
 {*****************************************************************************
 {*****************************************************************************
                            TX86LOADNODE
                            TX86LOADNODE
@@ -91,10 +92,29 @@ implementation
             case target_info.system of
             case target_info.system of
               system_i386_linux,system_i386_android:
               system_i386_linux,system_i386_android:
                 begin
                 begin
-                  location.reference.segment:=NR_GS;
                   case current_settings.tlsmodel of
                   case current_settings.tlsmodel of
                     tlsm_local:
                     tlsm_local:
-                      location.reference.refaddr:=addr_ntpoff;
+                      begin
+                        location.reference.segment:=NR_GS;
+                        location.reference.refaddr:=addr_ntpoff;
+                      end;
+                    tlsm_general:
+                      begin
+                        if not(cs_create_pic in current_settings.moduleswitches) then
+                          Internalerror(2018110701);
+                        reference_reset(href,0,[]);
+                        location.reference.index:=current_procinfo.got;
+                        location.reference.scalefactor:=1;
+                        location.reference.refaddr:=addr_tlsgd;
+                        cg.getcpuregister(current_asmdata.CurrAsmList,NR_EAX);
+                        current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_LEA,S_L,location.reference,NR_EAX));
+                        cg.g_call(current_asmdata.CurrAsmList,'___tls_get_addr');
+                        cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EAX);
+                        hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
+                        cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,NR_EAX,hregister);
+                        reference_reset(location.reference,location.reference.alignment,location.reference.volatility);
+                        location.reference.base:=hregister;
+                      end;
                     else
                     else
                       Internalerror(2018110401);
                       Internalerror(2018110401);
                   end;
                   end;

+ 0 - 2
rtl/inc/system.inc

@@ -1577,10 +1577,8 @@ end;
 { Generic threadmanager }
 { Generic threadmanager }
 {$i thread.inc}
 {$i thread.inc}
 
 
-{$ifndef FPC_SECTION_THREADVARS}
 { Generic threadvar support }
 { Generic threadvar support }
 {$i threadvr.inc}
 {$i threadvr.inc}
-{$endif FPC_SECTION_THREADVARS}
 
 
 {$ifdef DISABLE_NO_THREAD_MANAGER}
 {$ifdef DISABLE_NO_THREAD_MANAGER}
 { OS Dependent implementation }
 { OS Dependent implementation }

+ 4 - 3
rtl/inc/threadh.inc

@@ -110,10 +110,11 @@ Function SetThreadManager(Const NewTM : TThreadManager; Var OldTM : TThreadManag
 Function SetThreadManager(Const NewTM : TThreadManager) : Boolean;
 Function SetThreadManager(Const NewTM : TThreadManager) : Boolean;
 {$ifndef DISABLE_NO_THREAD_MANAGER}
 {$ifndef DISABLE_NO_THREAD_MANAGER}
 {$endif DISABLE_NO_THREAD_MANAGER}
 {$endif DISABLE_NO_THREAD_MANAGER}
-// Needs to be exported, so the manager can call it.
-{$ifndef FPC_SECTION_THREADVARS}
+{ Needs to be exported, so the manager can call it.
+  It needs to be exported even if FPC_SECTION_THREADVARS is set as it relocates also the
+  heap
+}
 procedure InitThreadVars(RelocProc : TRelocateThreadVarHandler);
 procedure InitThreadVars(RelocProc : TRelocateThreadVarHandler);
-{$endif FPC_SECTION_THREADVARS}
 procedure InitThread(stklen:SizeUInt);
 procedure InitThread(stklen:SizeUInt);
 procedure DoneThread;
 procedure DoneThread;
 
 

+ 7 - 0
rtl/linux/i386/si_prc.inc

@@ -47,6 +47,13 @@ function fpc_geteipasebxlocal : pointer; [external name 'fpc_geteipasebx'];
 
 
 procedure InitTLS; [external name 'FPC_INITTLS'];
 procedure InitTLS; [external name 'FPC_INITTLS'];
 
 
+
+{ so far, I found no case where this is actually called, so it is a dummy so far (FK) }
+function ___tls_get_addr(p : pointer) : pointer; public name '___tls_get_addr';
+  begin
+  end;
+
+
 procedure _FPC_proc_start; assembler; nostackframe; public name '_start';
 procedure _FPC_proc_start; assembler; nostackframe; public name '_start';
 asm
 asm
   { First locate the start of the environment variables }
   { First locate the start of the environment variables }

+ 19 - 6
rtl/linux/system.pp

@@ -496,6 +496,7 @@ end;
 procedure InitTLS; [public,alias:'FPC_INITTLS'];
 procedure InitTLS; [public,alias:'FPC_INITTLS'];
   const
   const
     PT_TLS = 7;
     PT_TLS = 7;
+    PT_DYNAMIC = 2;
 
 
   type
   type
     tphdr = record
     tphdr = record
@@ -536,18 +537,30 @@ procedure InitTLS; [public,alias:'FPC_INITTLS'];
         inc(auxp,2);
         inc(auxp,2);
       end;
       end;
     found:=false;
     found:=false;
+    size:=0;
     for i:=1 to phnum do
     for i:=1 to phnum do
       begin
       begin
-        if phdr^.p_type=PT_TLS then
-          begin
-            found:=true;
-            break;
-          end;
+        case phdr^.p_type of
+          PT_TLS:
+            begin
+              found:=true;
+              inc(size,phdr^.p_memsz);
+              size:=Align(size,phdr^.p_align);
+            end;
+          PT_DYNAMIC:
+            { if the program header contains a dynamic section, the program
+              is linked dynamically so the dynamic linker takes care of the
+              allocation of the TLS segment.
+
+              We cannot allocate it by ourself anyways as PT_TLS provides only
+              the size of TLS data of the executable itself
+             }
+            exit;
+        end;
         inc(phdr);
         inc(phdr);
       end;
       end;
     if found then
     if found then
       begin
       begin
-        size:=phdr^.p_memsz;
 {$ifdef CPUI386}
 {$ifdef CPUI386}
         { threadvars should start at a page boundary,
         { threadvars should start at a page boundary,
           add extra space for the TCB }
           add extra space for the TCB }

+ 5 - 3
rtl/unix/cthreads.pp

@@ -233,7 +233,9 @@ Type  PINTRTLEvent = ^TINTRTLEvent;
 
 
     procedure CReleaseThreadVars;
     procedure CReleaseThreadVars;
       begin
       begin
+{$ifndef FPC_SECTION_THREADVARS}
         Fpmunmap(pointer(pthread_getspecific(tlskey)),threadvarblocksize);
         Fpmunmap(pointer(pthread_getspecific(tlskey)),threadvarblocksize);
+{$endif FPC_SECTION_THREADVARS}
       end;
       end;
 
 
 { Include OS independent Threadvar initialization }
 { Include OS independent Threadvar initialization }
@@ -300,9 +302,11 @@ Type  PINTRTLEvent = ^TINTRTLEvent;
         fpwrite(0,s[1],length(s));
         fpwrite(0,s[1],length(s));
 {$endif DEBUG_MT}
 {$endif DEBUG_MT}
         ti:=pthreadinfo(param)^;
         ti:=pthreadinfo(param)^;
-        dispose(pthreadinfo(param));
+
         { Initialize thread }
         { Initialize thread }
         InitThread(ti.stklen);
         InitThread(ti.stklen);
+
+        dispose(pthreadinfo(param));
         { Start thread function }
         { Start thread function }
 {$ifdef DEBUG_MT}
 {$ifdef DEBUG_MT}
         writeln('Jumping to thread function');
         writeln('Jumping to thread function');
@@ -323,9 +327,7 @@ Type  PINTRTLEvent = ^TINTRTLEvent;
       begin
       begin
         { We're still running in single thread mode, setup the TLS }
         { We're still running in single thread mode, setup the TLS }
         pthread_key_create(@TLSKey,nil);
         pthread_key_create(@TLSKey,nil);
-{$ifndef FPC_SECTION_THREADVARS}
         InitThreadVars(@CRelocateThreadvar);
         InitThreadVars(@CRelocateThreadvar);
-{$endif FPC_SECTION_THREADVARS}
         { used to clean up threads that we did not create ourselves:
         { used to clean up threads that we did not create ourselves:
            a) the default value for a key (and hence also this one) in
            a) the default value for a key (and hence also this one) in
               new threads is NULL, and if it's still like that when the
               new threads is NULL, and if it's still like that when the