汇编-线程安全局部变量

问题描述

| 我正在尝试在汇编程序中使用线程安全的局部变量。 我已经在网上搜索过,但没有发现任何简单的东西。 我目前正在使用GCC汇编程序,因为该程序是C代码和汇编的混合,但是最终程序将包含用于多平台/调用约定的代码。 现在,我已经使用
.lcomm
伪操作声明了变量。 据我了解,这些变量将放在“ 1”部分。 所以我想它们将被所有线程共享。 是否可以直接在汇编中使用某种TLS变量,还是应该使用特定于平台的实现,例如Windows上的
pthread
__declspec
? 希望它足够清楚。不要犹豫,询问是否需要更多信息。 谢谢大家, 编辑 这是有问题的代码:
.lcomm  stack0,8
.lcomm  stack1,8

.globl _XSRuntime_CallMethod
_XSRuntime_CallMethod:

    pushq   %rbp
    movq    %rsp,%rbp

    xor     %rax,%rax

    popq    stack0( %rip )
    popq    stack1( %rip )

    callq   *%rdi

    pushq   stack1( %rip )
    pushq   stack0( %rip )

    leave
    ret
基本上,它用于将调用重定向到C函数。 C原型是:
extern uint64_t XSRuntime_CallMethod( void ( *m )( void * self,... ),... );
它以函数指针作为第一个参数,因此是
callq   *%rdi
,因为我正在使用系统V ABI对其进行测试。 汇编代码非常简单,我想保持这种方式,因此可以轻松维护。 问题是:如何使
stack0
stack1
变量安全。     

解决方法

不太熟悉汇编器,所以:
.lcomm  stack0,8
.lcomm  stack1,8

.globl _XSRuntime_CallMethod
_XSRuntime_CallMethod:

    pushq   %rbp // save BP
    movq    %rsp,%rbp // load BP with SP

    xor     %rax,%rax  // clear AX

    popq    stack0( %rip )  // pop return address into STACK0
    popq    stack1( %rip )  // pop flags into stack1

    callq   *%rdi  // call the indirect procedure,so putting flags/return to         XSRuntime_CallMethod onto stack

    pushq   stack1( %rip ) // put caller flags onto stack
    pushq   stack0( %rip ) // put caller return onto stack

    leave // clean passed parameters from stack
    ret   // and back to caller
是这样的吗? 如果是这样,跳到间接过程而不是调用它会不会更容易?然后,您不需要任何其他变量来保存调用者标志/返回,并且间接过程将直接返回给调用者。 只是一个建议-自从我做汇编程序以来。 如果必须将调用方地址存储在某个位置,请先确定SP,然后输入(输入?)并使用堆栈帧。在某些时候,其他任何事情都可能是线程不安全的。 Rgds, 马丁 好吧,使用TLS可能不是线程不安全的,但是任何递归调用呢?您最终在TLS中拥有另一个堆栈来覆盖此内容,因此您也可以使用\'SP \'堆栈 马丁     ,您认为编译器如何实现线程局部变量?尝试使用-S或/ FAs编译这样的程序,您将会看到。提示:它必须依赖于操作系统特定的API或其他详细信息才能访问TLS存储。有时,准备步骤隐藏在CRT中,但是没有唯一的方法可以做到。 例如,这是最近的MSVC的运行方式:
_TLS    SEGMENT
?number@@3HA DD 01H DUP (?)             ; number
_TLS    ENDS
EXTRN   __tls_array:DWORD
EXTRN   __tls_index:DWORD
_TEXT   SEGMENT
[...]
mov eax,DWORD PTR __tls_index
mov ecx,DWORD PTR fs:__tls_array
mov edx,DWORD PTR [ecx+eax*4]
mov eax,DWORD PTR ?number@@3HA[edx]
如您所见,它使用由CRT初始化的特殊变量。 在最新的Linux上,GCC可以使用TLS特定的重定位:
.globl number
    .section    .tbss,\"awT\",@nobits
number:
    .zero   4
    .text
    [...]
    movl    %gs:number@NTPOFF,%eax
如果您希望具有可移植性,那么最好不要依赖于此类特定于操作系统的详细信息,而应使用诸如pthread之类的通用API或使用Martin提出的基于堆栈的方法。但是我想,如果您想要可移植性,就不要使用汇编程序:)     ,?? \'Classic \'局部变量,即通过堆栈偏移量访问的参数/变量/结果本质上是线程安全的。 如果需要平台无关的\'TLS \',则在恢复所有线程之前,在线程字段中将一些合适的struct / class实例作为创建参数传递到所有线程中,然后恢复所有线程,将第一条消息发送到线程输入队列,或者随你... Rgds, 马丁     ,如前所述,局部变量(基于堆栈)本质上是线程安全的,因为每个线程都有自己的堆栈。 所有线程(不是基于堆栈的)都可以访问的线程安全变量可能最好使用自旋锁(或Windows NT引擎中的等效部分,关键部分)实现。此类变量必须在访问之前锁定,访问然后解锁。一种变体可能是读取是免费的,但是必须通过锁定/解锁来限制写入。 仅AFAIK编译器本身不实现线程安全变量。相反,它们提供了访问所需OS功能的lib函数。     ,您可能应该使用pla12ѭ和
TlsFree
(或与之等效的其他OS)(进行调用)执行类似的操作。返回的索引可以一次存储在全局集中,只读变量易于使用。 根据var持有的内容以及使用它们的代码的作用,您也许可以摆脱原子操作的束缚,但这可能会产生其自身的问题。     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...