mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-08 04:48:07 +02:00
+ i386-linux support for tls-based threadvars
git-svn-id: trunk@40272 -
This commit is contained in:
parent
0d50a63c7d
commit
063415fa72
@ -126,7 +126,10 @@ interface
|
||||
,addr_gottpoff
|
||||
,addr_tpoff
|
||||
{$ENDIF}
|
||||
|
||||
{$IFDEF i386}
|
||||
,addr_ntpoff
|
||||
,addr_tlsgd
|
||||
{$ENDIF}
|
||||
);
|
||||
|
||||
|
||||
|
@ -164,20 +164,25 @@ interface
|
||||
owner.writer.AsmWrite(symbol.name);
|
||||
if assigned(relsymbol) then
|
||||
owner.writer.AsmWrite('-'+relsymbol.name);
|
||||
if ref.refaddr=addr_pic then
|
||||
begin
|
||||
{ @GOT and @GOTPCREL references are only allowed for symbol alone,
|
||||
indexing, relsymbol or offset cannot be present. }
|
||||
if assigned(relsymbol) or (offset<>0) or (index<>NR_NO) then
|
||||
InternalError(2015011801);
|
||||
case ref.refaddr of
|
||||
addr_pic:
|
||||
begin
|
||||
{ @GOT and @GOTPCREL references are only allowed for symbol alone,
|
||||
indexing, relsymbol or offset cannot be present. }
|
||||
if assigned(relsymbol) or (offset<>0) or (index<>NR_NO) then
|
||||
InternalError(2015011801);
|
||||
{$ifdef x86_64}
|
||||
if (base<>NR_RIP) then
|
||||
InternalError(2015011802);
|
||||
owner.writer.AsmWrite('@GOTPCREL');
|
||||
if (base<>NR_RIP) then
|
||||
InternalError(2015011802);
|
||||
owner.writer.AsmWrite('@GOTPCREL');
|
||||
{$else x86_64}
|
||||
owner.writer.AsmWrite('@GOT');
|
||||
owner.writer.AsmWrite('@GOT');
|
||||
{$endif x86_64}
|
||||
end;
|
||||
end;
|
||||
addr_ntpoff:
|
||||
owner.writer.AsmWrite('@ntpoff');
|
||||
end;
|
||||
|
||||
if offset<0 then
|
||||
owner.writer.AsmWrite(tostr(offset))
|
||||
else
|
||||
@ -222,7 +227,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] then
|
||||
if o.ref^.refaddr in [addr_no,addr_pic,addr_pic_no_got,addr_ntpoff] then
|
||||
WriteReference(o.ref^)
|
||||
else
|
||||
begin
|
||||
|
@ -1098,6 +1098,7 @@ unit cgx86;
|
||||
procedure tcgx86.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
|
||||
var
|
||||
dirref,tmpref : treference;
|
||||
tmpreg : TRegister;
|
||||
begin
|
||||
dirref:=ref;
|
||||
|
||||
@ -1107,6 +1108,37 @@ unit cgx86;
|
||||
|
||||
with dirref do
|
||||
begin
|
||||
if refaddr=addr_ntpoff then
|
||||
begin
|
||||
{ Convert thread local address to a process global addres
|
||||
as we cannot handle far pointers.}
|
||||
case target_info.system of
|
||||
system_i386_linux,system_i386_android:
|
||||
if segment=NR_GS then
|
||||
begin
|
||||
reference_reset(tmpref,1,[]);
|
||||
tmpref.segment:=NR_GS;
|
||||
tmpreg:=getaddressregister(list);
|
||||
a_load_ref_reg(list,OS_ADDR,OS_ADDR,tmpref,tmpreg);
|
||||
reference_reset(tmpref,1,[]);
|
||||
tmpref.symbol:=symbol;
|
||||
tmpref.refaddr:=refaddr;
|
||||
tmpref.base:=tmpreg;
|
||||
if base<>NR_NO then
|
||||
tmpref.index:=base;
|
||||
list.concat(Taicpu.op_ref_reg(A_LEA,tcgsize2opsize[OS_ADDR],tmpref,tmpreg));
|
||||
segment:=NR_NO;
|
||||
base:=tmpreg;
|
||||
symbol:=nil;
|
||||
refaddr:=addr_no;
|
||||
end
|
||||
else
|
||||
Internalerror(2018110402);
|
||||
else
|
||||
Internalerror(2018110403);
|
||||
end;
|
||||
end;
|
||||
|
||||
if (base=NR_NO) and (index=NR_NO) then
|
||||
begin
|
||||
if assigned(dirref.symbol) then
|
||||
@ -1196,26 +1228,7 @@ unit cgx86;
|
||||
else
|
||||
a_load_reg_reg(list,OS_16,OS_16,segment,GetNextReg(r));
|
||||
{$else i8086}
|
||||
if (tf_section_threadvars in target_info.flags) then
|
||||
begin
|
||||
{ Convert thread local address to a process global addres
|
||||
as we cannot handle far pointers.}
|
||||
case target_info.system of
|
||||
system_i386_linux,system_i386_android:
|
||||
if segment=NR_GS then
|
||||
begin
|
||||
reference_reset_symbol(tmpref,current_asmdata.RefAsmSymbol('___fpc_threadvar_offset',AT_DATA),0,sizeof(pint),[]);
|
||||
tmpref.segment:=NR_GS;
|
||||
list.concat(Taicpu.op_ref_reg(A_ADD,tcgsize2opsize[OS_ADDR],tmpref,r));
|
||||
end
|
||||
else
|
||||
cgmessage(cg_e_cant_use_far_pointer_there);
|
||||
else
|
||||
cgmessage(cg_e_cant_use_far_pointer_there);
|
||||
end;
|
||||
end
|
||||
else
|
||||
cgmessage(cg_e_cant_use_far_pointer_there);
|
||||
cgmessage(cg_e_cant_use_far_pointer_there);
|
||||
{$endif i8086}
|
||||
end;
|
||||
end;
|
||||
@ -2774,6 +2787,24 @@ unit cgx86;
|
||||
make_simple_ref(list,srcref);
|
||||
make_simple_ref(list,dstref);
|
||||
{$endif not i8086}
|
||||
{$ifdef i386}
|
||||
{ we could handle "far" pointers here, but reloading es/ds is probably much slower
|
||||
than just resolving the tls segment }
|
||||
if (srcref.refaddr=addr_ntpoff) and (srcref.segment=NR_GS) then
|
||||
begin
|
||||
r:=getaddressregister(list);
|
||||
a_loadaddr_ref_reg(list,srcref,r);
|
||||
reference_reset(srcref,srcref.alignment,srcref.volatility);
|
||||
srcref.base:=r;
|
||||
end;
|
||||
if (dstref.refaddr=addr_ntpoff) and (dstref.segment=NR_GS) then
|
||||
begin
|
||||
r:=getaddressregister(list);
|
||||
a_loadaddr_ref_reg(list,dstref,r);
|
||||
reference_reset(dstref,dstref.alignment,dstref.volatility);
|
||||
dstref.base:=r;
|
||||
end;
|
||||
{$endif i386}
|
||||
cm:=copy_move;
|
||||
helpsize:=3*sizeof(aword);
|
||||
if cs_opt_size in current_settings.optimizerswitches then
|
||||
@ -2811,8 +2842,9 @@ unit cgx86;
|
||||
not(len in copy_len_sizes) then
|
||||
cm:=copy_string;
|
||||
{$ifndef i8086}
|
||||
if (srcref.segment<>NR_NO) or
|
||||
(dstref.segment<>NR_NO) then
|
||||
{ using %fs and %gs as segment prefixes is perfectly valid }
|
||||
if ((srcref.segment<>NR_NO) and (srcref.segment<>NR_FS) and (srcref.segment<>NR_GS)) or
|
||||
((dstref.segment<>NR_NO) and (dstref.segment<>NR_FS) and (dstref.segment<>NR_GS)) then
|
||||
cm:=copy_string;
|
||||
{$endif not i8086}
|
||||
case cm of
|
||||
@ -3004,8 +3036,8 @@ unit cgx86;
|
||||
else {copy_string, should be a good fallback in case of unhandled}
|
||||
begin
|
||||
getcpuregister(list,REGDI);
|
||||
if (dest.segment=NR_NO) and
|
||||
(segment_regs_equal(NR_SS,NR_DS) or ((dest.base<>NR_BP) and (dest.base<>NR_SP))) then
|
||||
if (dstref.segment=NR_NO) and
|
||||
(segment_regs_equal(NR_SS,NR_DS) or ((dstref.base<>NR_BP) and (dstref.base<>NR_SP))) then
|
||||
begin
|
||||
a_loadaddr_ref_reg(list,dstref,REGDI);
|
||||
saved_es:=false;
|
||||
@ -3024,9 +3056,9 @@ unit cgx86;
|
||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_ES));
|
||||
saved_es:=true;
|
||||
{$endif volatile_es}
|
||||
if dest.segment<>NR_NO then
|
||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,dest.segment))
|
||||
else if (dest.base=NR_BP) or (dest.base=NR_SP) then
|
||||
if dstref.segment<>NR_NO then
|
||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,dstref.segment))
|
||||
else if (dstref.base=NR_BP) or (dstref.base=NR_SP) then
|
||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_SS))
|
||||
else
|
||||
internalerror(2014040401);
|
||||
@ -3044,8 +3076,8 @@ unit cgx86;
|
||||
srcref.index:=NR_NO;
|
||||
end;
|
||||
{$endif i8086}
|
||||
if ((source.segment=NR_NO) and (segment_regs_equal(NR_SS,NR_DS) or ((source.base<>NR_BP) and (source.base<>NR_SP)))) or
|
||||
(is_segment_reg(source.segment) and segment_regs_equal(source.segment,NR_DS)) then
|
||||
if ((srcref.segment=NR_NO) and (segment_regs_equal(NR_SS,NR_DS) or ((srcref.base<>NR_BP) and (srcref.base<>NR_SP)))) or
|
||||
(is_segment_reg(srcref.segment) and segment_regs_equal(srcref.segment,NR_DS)) then
|
||||
begin
|
||||
srcref.segment:=NR_NO;
|
||||
a_loadaddr_ref_reg(list,srcref,REGSI);
|
||||
@ -3057,9 +3089,9 @@ unit cgx86;
|
||||
a_loadaddr_ref_reg(list,srcref,REGSI);
|
||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_DS));
|
||||
saved_ds:=true;
|
||||
if source.segment<>NR_NO then
|
||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,source.segment))
|
||||
else if (source.base=NR_BP) or (source.base=NR_SP) then
|
||||
if srcref.segment<>NR_NO then
|
||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,srcref.segment))
|
||||
else if (srcref.base=NR_BP) or (srcref.base=NR_SP) then
|
||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_SS))
|
||||
else
|
||||
internalerror(2014040402);
|
||||
|
@ -38,6 +38,7 @@ interface
|
||||
implementation
|
||||
|
||||
uses
|
||||
globals,
|
||||
cutils,verbose,systems,
|
||||
aasmbase,aasmtai,aasmdata,
|
||||
cgutils,cgobj,
|
||||
@ -88,7 +89,15 @@ implementation
|
||||
begin
|
||||
case target_info.system of
|
||||
system_i386_linux,system_i386_android:
|
||||
location.reference.segment:=NR_GS;
|
||||
begin
|
||||
location.reference.segment:=NR_GS;
|
||||
case current_settings.tlsmodel of
|
||||
tlsm_local:
|
||||
location.reference.refaddr:=addr_ntpoff;
|
||||
else
|
||||
Internalerror(2018110401);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
@ -45,6 +45,8 @@ var
|
||||
function fpc_geteipasebxlocal : pointer; [external name 'fpc_geteipasebx'];
|
||||
{$endif}
|
||||
|
||||
procedure InitTLS; [external name 'FPC_INITTLS'];
|
||||
|
||||
procedure _FPC_proc_start; assembler; nostackframe; public name '_start';
|
||||
asm
|
||||
{ First locate the start of the environment variables }
|
||||
@ -93,6 +95,8 @@ asm
|
||||
movl %esp,initialstkptr
|
||||
{$endif FPC_PIC}
|
||||
|
||||
call InitTLS
|
||||
|
||||
xorl %ebp,%ebp
|
||||
call PASCALMAIN
|
||||
end;
|
||||
|
@ -442,13 +442,56 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
{$ifdef CPUARM}
|
||||
|
||||
Function fpset_tls(p : pointer):cint;
|
||||
{$if defined(CPUARM)}
|
||||
{$define INITTLS}
|
||||
Function fpset_tls(p : pointer;size : SizeUInt):cint;
|
||||
begin
|
||||
Result:=do_syscall(__ARM_NR_set_tls,TSysParam(p));
|
||||
Result:=do_syscall(__ARM_NR_set_tls,TSysParam(p));
|
||||
end;
|
||||
{$endif defined(CPUARM)}
|
||||
|
||||
{$if defined(CPUI386)}
|
||||
{$define INITTLS}
|
||||
Function fpset_tls(p : pointer;size : SizeUInt):cint;
|
||||
var
|
||||
desc : record
|
||||
entry_number : dword;
|
||||
base_addr : dword;
|
||||
limit : dword;
|
||||
flags : dword;
|
||||
end;
|
||||
selector : word;
|
||||
begin
|
||||
// get descriptor from the kernel
|
||||
desc.entry_number:=$ffffffff;
|
||||
// TLS is accessed by negative offsets, only the TCB pointer is at offset 0
|
||||
desc.base_addr:=dword(p)+size-SizeOf(Pointer);
|
||||
// 4 GB, limit is given in pages
|
||||
desc.limit:=$fffff;
|
||||
// seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1
|
||||
desc.flags:=%1010001;
|
||||
Result:=do_syscall(syscall_nr_set_thread_area,TSysParam(@desc));
|
||||
if Result=0 then
|
||||
begin
|
||||
selector:=desc.entry_number*8+3;
|
||||
asm
|
||||
movw selector,%gs
|
||||
movl desc.base_addr,%eax
|
||||
movl %eax,%gs:0
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
{$endif defined(CPUI386)}
|
||||
|
||||
{$ifdef INITTLS}
|
||||
{ This code initialized the TLS segment for single threaded and static programs.
|
||||
|
||||
In case of multithreaded and/or dynamically linked programs it is assumed that they
|
||||
dependent anyways on glibc which initializes tls properly.
|
||||
|
||||
As soon as a purely FPC dynamic loading or multithreading is implemented, the code
|
||||
needs to be extended to handle these cases as well.
|
||||
}
|
||||
|
||||
procedure InitTLS; [public,alias:'FPC_INITTLS'];
|
||||
const
|
||||
@ -474,11 +517,12 @@ procedure InitTLS; [public,alias:'FPC_INITTLS'];
|
||||
tls : pointer;
|
||||
auxp : ppointer;
|
||||
found : boolean;
|
||||
size : SizeUInt;
|
||||
begin
|
||||
auxp:=ppointer(envp);
|
||||
{ skip environment }
|
||||
while assigned(auxp^) do
|
||||
inc(auxp);
|
||||
inc(auxp);
|
||||
inc(auxp);
|
||||
{ now we are at the auxillary vector }
|
||||
while assigned(auxp^) do
|
||||
@ -503,8 +547,14 @@ procedure InitTLS; [public,alias:'FPC_INITTLS'];
|
||||
end;
|
||||
if found then
|
||||
begin
|
||||
tls:=Fpmmap(nil,phdr^.p_memsz,3,MAP_PRIVATE+MAP_ANONYMOUS,-1,0);
|
||||
fpset_tls(tls);
|
||||
size:=phdr^.p_memsz;
|
||||
{$ifdef CPUI386}
|
||||
{ threadvars should start at a page boundary,
|
||||
add extra space for the TCB }
|
||||
size:=Align(size,4096)+sizeof(Pointer);
|
||||
{$endif CPUI386}
|
||||
tls:=Fpmmap(nil,size,3,MAP_PRIVATE+MAP_ANONYMOUS,-1,0);
|
||||
fpset_tls(tls,size);
|
||||
end;
|
||||
end;
|
||||
{$endif CPUARM}
|
||||
|
Loading…
Reference in New Issue
Block a user