2017-08-09 313 views
0

作为尝试实现对cgo的msvc支持的一部分,我发现我需要将一些内联gcc汇编移植到ml64。这里是原来的装配:将gcc内联汇编转换为ml64

ts = *(ThreadStart*)v; 

/* 
* Set specific keys in thread local storage. 
*/ 
__asm { 
     "movq %0, %%gs:0x28\n" // MOVL tls0, 0x28(GS) 
     "movq %%gs:0x28, %%rax\n" // MOVQ 0x28(GS), tmp 
     "movq %1, 0(%%rax)\n" // MOVQ g, 0(GS) 
     :: "r"(ts.tls), "r"(ts.g) : "%rax" 
} 

这里是我所创建的外部汇编文件:

PUBLIC msvc_windows_amd64_threadentry 

.CODE 
    msvc_windows_amd64_threadentry PROC 

     MOV gs:[0x28], ts.tls 
     MOV rax, gs:[0x28] 
     MOV gs:[0], ts.g 

     ret 
    msvc_windows_amd64_threadentry ENDP 
END 

显然存在着一些问题。首先,我不知道如何让组装者知道ts的结构; gcc显然知道它,因为它在被编译的文件中,但msvc不支持amd64内联汇编。另一种是我认为我可以像extern函数一样调用msvc_windows_amd64_threadentry,但我不完全确定。老实说,我从来没有必须处理组装,所以我从来没有遇到过这些问题。

+4

你的主要问题是,这是Linux线程本地存储。 Windows线程本地存储是完全不同的,所以即使你可以让该程序集与你的编译器一起工作,它也不会在windows上运行。 –

+1

完全取决于你想要做的事情。如果您不介意依赖C11,则重写代码以使用'thread_local'。 –

+0

“原始程序集”示例中的内联程序集不必要的复杂。只有第一个汇编语句需要内联汇编,最后两个语句可以用普通的C语言编写。第三个语句也与同一行中给出的注释不匹配。 –

回答

2

您根本不需要使用程序集来将此代码移植到Microsoft C++。您可以使用__writegsqword内部函数替换第一个汇编指令,然后使用普通C代替最后两个汇编指令。例如:

__writegsqword(0x28, (unsigned long long) ts.tls); 
*(void **)ts.tls = (void *) ts.g; 

注意的是,根据种类的ts.tlsts.g你可能会用不同的类型转换更好或可以完全避免。

您可以通过添加这样的函数使用与GCC和Microsoft C++相同的代码:

#ifdef __GNUC__ 
static inline void 
__writegsqword(unsigned long long offset, unsigned long long value) { 
    asm("movq %0,%%gs:%1" :: "re" (value), "m" (*(int *)offset)); 
} 
#endif 
+0

非常感谢。我并不期待管理外部程序集文件。 – xaav