From 72416edcc465a6f9a9fea43c4219566750fb8db8 Mon Sep 17 00:00:00 2001 From: florian Date: Sun, 11 Nov 2018 17:32:20 +0000 Subject: [PATCH] + support for tlsm_general on i386-linux git-svn-id: trunk@40281 - --- compiler/i386/aoptcpu.pas | 2 +- compiler/i386/cpupi.pas | 9 ++++++++- compiler/x86/aasmcpu.pas | 5 ++++- compiler/x86/agx86att.pas | 4 +++- compiler/x86/nx86ld.pas | 28 ++++++++++++++++++++++++---- rtl/inc/system.inc | 2 -- rtl/inc/threadh.inc | 7 ++++--- rtl/linux/i386/si_prc.inc | 7 +++++++ rtl/linux/system.pp | 25 +++++++++++++++++++------ rtl/unix/cthreads.pp | 8 +++++--- 10 files changed, 75 insertions(+), 22 deletions(-) diff --git a/compiler/i386/aoptcpu.pas b/compiler/i386/aoptcpu.pas index ddb9037354..35f66d9609 100644 --- a/compiler/i386/aoptcpu.pas +++ b/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 diff --git a/compiler/i386/cpupi.pas b/compiler/i386/cpupi.pas index 968ae8bbe4..d19409bdcc 100644 --- a/compiler/i386/cpupi.pas +++ b/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; diff --git a/compiler/x86/aasmcpu.pas b/compiler/x86/aasmcpu.pas index c2093604fa..761f869a00 100644 --- a/compiler/x86/aasmcpu.pas +++ b/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 diff --git a/compiler/x86/agx86att.pas b/compiler/x86/agx86att.pas index 96a20e71e7..b1f71a966f 100644 --- a/compiler/x86/agx86att.pas +++ b/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 diff --git a/compiler/x86/nx86ld.pas b/compiler/x86/nx86ld.pas index c8708a72c3..faa14b697b 100644 --- a/compiler/x86/nx86ld.pas +++ b/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; diff --git a/rtl/inc/system.inc b/rtl/inc/system.inc index 15e698ab75..1191725cf7 100644 --- a/rtl/inc/system.inc +++ b/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 } diff --git a/rtl/inc/threadh.inc b/rtl/inc/threadh.inc index 30942afc80..9b52769ab3 100644 --- a/rtl/inc/threadh.inc +++ b/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; diff --git a/rtl/linux/i386/si_prc.inc b/rtl/linux/i386/si_prc.inc index 96e0b3e704..fd1aaa38fd 100644 --- a/rtl/linux/i386/si_prc.inc +++ b/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 } diff --git a/rtl/linux/system.pp b/rtl/linux/system.pp index 815469401c..f7f5e5d4c4 100644 --- a/rtl/linux/system.pp +++ b/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 } diff --git a/rtl/unix/cthreads.pp b/rtl/unix/cthreads.pp index e6067e21aa..6ac4e5fcd3 100644 --- a/rtl/unix/cthreads.pp +++ b/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