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

+ 8 - 1
compiler/i386/cpupi.pas

@@ -95,11 +95,18 @@ unit cpupi;
           para_stack_size := 0;
       end;
 
+
     procedure tcpuprocinfo.allocate_got_register(list: tasmlist);
       begin
         if (cs_create_pic in current_settings.moduleswitches) then
           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;
 

+ 4 - 1
compiler/x86/aasmcpu.pas

@@ -1901,7 +1901,10 @@ implementation
             { Switching index to base position gives shorter assembler 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
-               (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
                 ref.base:=ref.index;
                 if ref.scalefactor=2 then

+ 3 - 1
compiler/x86/agx86att.pas

@@ -182,6 +182,8 @@ interface
 {$ifdef i386}
              addr_ntpoff:
                owner.writer.AsmWrite('@ntpoff');
+             addr_tlsgd:
+               owner.writer.AsmWrite('@tlsgd');
 {$endif i386}
            end;
 
@@ -229,7 +231,7 @@ interface
             else
               owner.writer.AsmWrite(gas_regname(o.reg));
           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^)
             else
               begin

+ 24 - 4
compiler/x86/nx86ld.pas

@@ -40,10 +40,11 @@ implementation
     uses
       globals,
       cutils,verbose,systems,
-      aasmbase,aasmtai,aasmdata,
+      aasmbase,aasmtai,aasmdata,aasmcpu,
       cgutils,cgobj,
       symconst,symdef,symtable,
-      cgbase,cpubase,parabase,paramgr;
+      cgbase,cpubase,parabase,paramgr,
+      procinfo;
 
 {*****************************************************************************
                            TX86LOADNODE
@@ -91,10 +92,29 @@ implementation
             case target_info.system of
               system_i386_linux,system_i386_android:
                 begin
-                  location.reference.segment:=NR_GS;
                   case current_settings.tlsmodel of
                     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
                       Internalerror(2018110401);
                   end;

+ 0 - 2
rtl/inc/system.inc

@@ -1577,10 +1577,8 @@ end;
 { Generic threadmanager }
 {$i thread.inc}
 
-{$ifndef FPC_SECTION_THREADVARS}
 { Generic threadvar support }
 {$i threadvr.inc}
-{$endif FPC_SECTION_THREADVARS}
 
 {$ifdef DISABLE_NO_THREAD_MANAGER}
 { 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;
 {$ifndef 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);
-{$endif FPC_SECTION_THREADVARS}
 procedure InitThread(stklen:SizeUInt);
 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'];
 
+
+{ 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';
 asm
   { 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'];
   const
     PT_TLS = 7;
+    PT_DYNAMIC = 2;
 
   type
     tphdr = record
@@ -536,18 +537,30 @@ procedure InitTLS; [public,alias:'FPC_INITTLS'];
         inc(auxp,2);
       end;
     found:=false;
+    size:=0;
     for i:=1 to phnum do
       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);
       end;
     if found then
       begin
-        size:=phdr^.p_memsz;
 {$ifdef CPUI386}
         { threadvars should start at a page boundary,
           add extra space for the TCB }

+ 5 - 3
rtl/unix/cthreads.pp

@@ -233,7 +233,9 @@ Type  PINTRTLEvent = ^TINTRTLEvent;
 
     procedure CReleaseThreadVars;
       begin
+{$ifndef FPC_SECTION_THREADVARS}
         Fpmunmap(pointer(pthread_getspecific(tlskey)),threadvarblocksize);
+{$endif FPC_SECTION_THREADVARS}
       end;
 
 { Include OS independent Threadvar initialization }
@@ -300,9 +302,11 @@ Type  PINTRTLEvent = ^TINTRTLEvent;
         fpwrite(0,s[1],length(s));
 {$endif DEBUG_MT}
         ti:=pthreadinfo(param)^;
-        dispose(pthreadinfo(param));
+
         { Initialize thread }
         InitThread(ti.stklen);
+
+        dispose(pthreadinfo(param));
         { Start thread function }
 {$ifdef DEBUG_MT}
         writeln('Jumping to thread function');
@@ -323,9 +327,7 @@ Type  PINTRTLEvent = ^TINTRTLEvent;
       begin
         { We're still running in single thread mode, setup the TLS }
         pthread_key_create(@TLSKey,nil);
-{$ifndef FPC_SECTION_THREADVARS}
         InitThreadVars(@CRelocateThreadvar);
-{$endif FPC_SECTION_THREADVARS}
         { used to clean up threads that we did not create ourselves:
            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