mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-27 20:11:02 +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_gottpoff
|
||||||
,addr_tpoff
|
,addr_tpoff
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
{$IFDEF i386}
|
||||||
|
,addr_ntpoff
|
||||||
|
,addr_tlsgd
|
||||||
|
{$ENDIF}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -164,20 +164,25 @@ interface
|
|||||||
owner.writer.AsmWrite(symbol.name);
|
owner.writer.AsmWrite(symbol.name);
|
||||||
if assigned(relsymbol) then
|
if assigned(relsymbol) then
|
||||||
owner.writer.AsmWrite('-'+relsymbol.name);
|
owner.writer.AsmWrite('-'+relsymbol.name);
|
||||||
if ref.refaddr=addr_pic then
|
case ref.refaddr of
|
||||||
begin
|
addr_pic:
|
||||||
{ @GOT and @GOTPCREL references are only allowed for symbol alone,
|
begin
|
||||||
indexing, relsymbol or offset cannot be present. }
|
{ @GOT and @GOTPCREL references are only allowed for symbol alone,
|
||||||
if assigned(relsymbol) or (offset<>0) or (index<>NR_NO) then
|
indexing, relsymbol or offset cannot be present. }
|
||||||
InternalError(2015011801);
|
if assigned(relsymbol) or (offset<>0) or (index<>NR_NO) then
|
||||||
|
InternalError(2015011801);
|
||||||
{$ifdef x86_64}
|
{$ifdef x86_64}
|
||||||
if (base<>NR_RIP) then
|
if (base<>NR_RIP) then
|
||||||
InternalError(2015011802);
|
InternalError(2015011802);
|
||||||
owner.writer.AsmWrite('@GOTPCREL');
|
owner.writer.AsmWrite('@GOTPCREL');
|
||||||
{$else x86_64}
|
{$else x86_64}
|
||||||
owner.writer.AsmWrite('@GOT');
|
owner.writer.AsmWrite('@GOT');
|
||||||
{$endif x86_64}
|
{$endif x86_64}
|
||||||
end;
|
end;
|
||||||
|
addr_ntpoff:
|
||||||
|
owner.writer.AsmWrite('@ntpoff');
|
||||||
|
end;
|
||||||
|
|
||||||
if offset<0 then
|
if offset<0 then
|
||||||
owner.writer.AsmWrite(tostr(offset))
|
owner.writer.AsmWrite(tostr(offset))
|
||||||
else
|
else
|
||||||
@ -222,7 +227,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] then
|
if o.ref^.refaddr in [addr_no,addr_pic,addr_pic_no_got,addr_ntpoff] then
|
||||||
WriteReference(o.ref^)
|
WriteReference(o.ref^)
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
|
@ -1098,6 +1098,7 @@ unit cgx86;
|
|||||||
procedure tcgx86.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
|
procedure tcgx86.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
|
||||||
var
|
var
|
||||||
dirref,tmpref : treference;
|
dirref,tmpref : treference;
|
||||||
|
tmpreg : TRegister;
|
||||||
begin
|
begin
|
||||||
dirref:=ref;
|
dirref:=ref;
|
||||||
|
|
||||||
@ -1107,6 +1108,37 @@ unit cgx86;
|
|||||||
|
|
||||||
with dirref do
|
with dirref do
|
||||||
begin
|
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
|
if (base=NR_NO) and (index=NR_NO) then
|
||||||
begin
|
begin
|
||||||
if assigned(dirref.symbol) then
|
if assigned(dirref.symbol) then
|
||||||
@ -1196,26 +1228,7 @@ unit cgx86;
|
|||||||
else
|
else
|
||||||
a_load_reg_reg(list,OS_16,OS_16,segment,GetNextReg(r));
|
a_load_reg_reg(list,OS_16,OS_16,segment,GetNextReg(r));
|
||||||
{$else i8086}
|
{$else i8086}
|
||||||
if (tf_section_threadvars in target_info.flags) then
|
cgmessage(cg_e_cant_use_far_pointer_there);
|
||||||
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);
|
|
||||||
{$endif i8086}
|
{$endif i8086}
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -2774,6 +2787,24 @@ unit cgx86;
|
|||||||
make_simple_ref(list,srcref);
|
make_simple_ref(list,srcref);
|
||||||
make_simple_ref(list,dstref);
|
make_simple_ref(list,dstref);
|
||||||
{$endif not i8086}
|
{$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;
|
cm:=copy_move;
|
||||||
helpsize:=3*sizeof(aword);
|
helpsize:=3*sizeof(aword);
|
||||||
if cs_opt_size in current_settings.optimizerswitches then
|
if cs_opt_size in current_settings.optimizerswitches then
|
||||||
@ -2811,8 +2842,9 @@ unit cgx86;
|
|||||||
not(len in copy_len_sizes) then
|
not(len in copy_len_sizes) then
|
||||||
cm:=copy_string;
|
cm:=copy_string;
|
||||||
{$ifndef i8086}
|
{$ifndef i8086}
|
||||||
if (srcref.segment<>NR_NO) or
|
{ using %fs and %gs as segment prefixes is perfectly valid }
|
||||||
(dstref.segment<>NR_NO) then
|
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;
|
cm:=copy_string;
|
||||||
{$endif not i8086}
|
{$endif not i8086}
|
||||||
case cm of
|
case cm of
|
||||||
@ -3004,8 +3036,8 @@ unit cgx86;
|
|||||||
else {copy_string, should be a good fallback in case of unhandled}
|
else {copy_string, should be a good fallback in case of unhandled}
|
||||||
begin
|
begin
|
||||||
getcpuregister(list,REGDI);
|
getcpuregister(list,REGDI);
|
||||||
if (dest.segment=NR_NO) and
|
if (dstref.segment=NR_NO) and
|
||||||
(segment_regs_equal(NR_SS,NR_DS) or ((dest.base<>NR_BP) and (dest.base<>NR_SP))) then
|
(segment_regs_equal(NR_SS,NR_DS) or ((dstref.base<>NR_BP) and (dstref.base<>NR_SP))) then
|
||||||
begin
|
begin
|
||||||
a_loadaddr_ref_reg(list,dstref,REGDI);
|
a_loadaddr_ref_reg(list,dstref,REGDI);
|
||||||
saved_es:=false;
|
saved_es:=false;
|
||||||
@ -3024,9 +3056,9 @@ unit cgx86;
|
|||||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_ES));
|
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_ES));
|
||||||
saved_es:=true;
|
saved_es:=true;
|
||||||
{$endif volatile_es}
|
{$endif volatile_es}
|
||||||
if dest.segment<>NR_NO then
|
if dstref.segment<>NR_NO then
|
||||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,dest.segment))
|
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,dstref.segment))
|
||||||
else if (dest.base=NR_BP) or (dest.base=NR_SP) then
|
else if (dstref.base=NR_BP) or (dstref.base=NR_SP) then
|
||||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_SS))
|
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_SS))
|
||||||
else
|
else
|
||||||
internalerror(2014040401);
|
internalerror(2014040401);
|
||||||
@ -3044,8 +3076,8 @@ unit cgx86;
|
|||||||
srcref.index:=NR_NO;
|
srcref.index:=NR_NO;
|
||||||
end;
|
end;
|
||||||
{$endif i8086}
|
{$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
|
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(source.segment) and segment_regs_equal(source.segment,NR_DS)) then
|
(is_segment_reg(srcref.segment) and segment_regs_equal(srcref.segment,NR_DS)) then
|
||||||
begin
|
begin
|
||||||
srcref.segment:=NR_NO;
|
srcref.segment:=NR_NO;
|
||||||
a_loadaddr_ref_reg(list,srcref,REGSI);
|
a_loadaddr_ref_reg(list,srcref,REGSI);
|
||||||
@ -3057,9 +3089,9 @@ unit cgx86;
|
|||||||
a_loadaddr_ref_reg(list,srcref,REGSI);
|
a_loadaddr_ref_reg(list,srcref,REGSI);
|
||||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_DS));
|
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_DS));
|
||||||
saved_ds:=true;
|
saved_ds:=true;
|
||||||
if source.segment<>NR_NO then
|
if srcref.segment<>NR_NO then
|
||||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,source.segment))
|
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,srcref.segment))
|
||||||
else if (source.base=NR_BP) or (source.base=NR_SP) then
|
else if (srcref.base=NR_BP) or (srcref.base=NR_SP) then
|
||||||
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_SS))
|
list.concat(taicpu.op_reg(A_PUSH,push_segment_size,NR_SS))
|
||||||
else
|
else
|
||||||
internalerror(2014040402);
|
internalerror(2014040402);
|
||||||
|
@ -38,6 +38,7 @@ interface
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
|
globals,
|
||||||
cutils,verbose,systems,
|
cutils,verbose,systems,
|
||||||
aasmbase,aasmtai,aasmdata,
|
aasmbase,aasmtai,aasmdata,
|
||||||
cgutils,cgobj,
|
cgutils,cgobj,
|
||||||
@ -88,7 +89,15 @@ implementation
|
|||||||
begin
|
begin
|
||||||
case target_info.system of
|
case target_info.system of
|
||||||
system_i386_linux,system_i386_android:
|
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;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -45,6 +45,8 @@ var
|
|||||||
function fpc_geteipasebxlocal : pointer; [external name 'fpc_geteipasebx'];
|
function fpc_geteipasebxlocal : pointer; [external name 'fpc_geteipasebx'];
|
||||||
{$endif}
|
{$endif}
|
||||||
|
|
||||||
|
procedure InitTLS; [external name 'FPC_INITTLS'];
|
||||||
|
|
||||||
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 }
|
||||||
@ -93,6 +95,8 @@ asm
|
|||||||
movl %esp,initialstkptr
|
movl %esp,initialstkptr
|
||||||
{$endif FPC_PIC}
|
{$endif FPC_PIC}
|
||||||
|
|
||||||
|
call InitTLS
|
||||||
|
|
||||||
xorl %ebp,%ebp
|
xorl %ebp,%ebp
|
||||||
call PASCALMAIN
|
call PASCALMAIN
|
||||||
end;
|
end;
|
||||||
|
@ -442,13 +442,56 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{$ifdef CPUARM}
|
{$if defined(CPUARM)}
|
||||||
|
{$define INITTLS}
|
||||||
Function fpset_tls(p : pointer):cint;
|
Function fpset_tls(p : pointer;size : SizeUInt):cint;
|
||||||
begin
|
begin
|
||||||
Result:=do_syscall(__ARM_NR_set_tls,TSysParam(p));
|
Result:=do_syscall(__ARM_NR_set_tls,TSysParam(p));
|
||||||
end;
|
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'];
|
procedure InitTLS; [public,alias:'FPC_INITTLS'];
|
||||||
const
|
const
|
||||||
@ -474,11 +517,12 @@ procedure InitTLS; [public,alias:'FPC_INITTLS'];
|
|||||||
tls : pointer;
|
tls : pointer;
|
||||||
auxp : ppointer;
|
auxp : ppointer;
|
||||||
found : boolean;
|
found : boolean;
|
||||||
|
size : SizeUInt;
|
||||||
begin
|
begin
|
||||||
auxp:=ppointer(envp);
|
auxp:=ppointer(envp);
|
||||||
{ skip environment }
|
{ skip environment }
|
||||||
while assigned(auxp^) do
|
while assigned(auxp^) do
|
||||||
inc(auxp);
|
inc(auxp);
|
||||||
inc(auxp);
|
inc(auxp);
|
||||||
{ now we are at the auxillary vector }
|
{ now we are at the auxillary vector }
|
||||||
while assigned(auxp^) do
|
while assigned(auxp^) do
|
||||||
@ -503,8 +547,14 @@ procedure InitTLS; [public,alias:'FPC_INITTLS'];
|
|||||||
end;
|
end;
|
||||||
if found then
|
if found then
|
||||||
begin
|
begin
|
||||||
tls:=Fpmmap(nil,phdr^.p_memsz,3,MAP_PRIVATE+MAP_ANONYMOUS,-1,0);
|
size:=phdr^.p_memsz;
|
||||||
fpset_tls(tls);
|
{$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;
|
||||||
end;
|
end;
|
||||||
{$endif CPUARM}
|
{$endif CPUARM}
|
||||||
|
Loading…
Reference in New Issue
Block a user