【发布时间】:2021-12-05 20:33:24
【问题描述】:
包括组件。这个周末我试图让我自己的小型库在没有任何 C 库的情况下运行,而线程本地的东西给我带来了问题。您可以在下面看到我创建了一个名为Try1 的结构(因为这是我的第一次尝试!)如果我设置线程局部变量并使用它,代码似乎执行得很好。如果我使用全局变量在 Try1 上调用 const 方法,它似乎运行良好。现在,如果我两者都做,那就不好了。尽管我能够访问成员并使用全局变量运行该函数,但它还是会出现段错误。该代码将打印 Hello 和 Hello2 但不是 Hello3
我怀疑问题出在变量的地址上。我尝试使用 if 语句打印第一个 hello。 if ((s64)&t1 > (s64)buf+1024*16) 这是真的,所以这意味着指针不在我认为的位置。它也不是 gdb 建议的 -8(这是一个有符号比较,我尝试了 0 而不是 buf)
在 c++ 代码下汇编。第一行是第一次调用 write
//test.cpp
//clang++ or g++ -std=c++20 -g -fno-rtti -fno-exceptions -fno-stack-protector -fno-asynchronous-unwind-tables -static -nostdlib test.cpp -march=native && ./a.out
#include <immintrin.h>
typedef unsigned long long int u64;
ssize_t my_write(int fd, const void *buf, size_t size) {
register int64_t rax __asm__ ("rax") = 1;
register int rdi __asm__ ("rdi") = fd;
register const void *rsi __asm__ ("rsi") = buf;
register size_t rdx __asm__ ("rdx") = size;
__asm__ __volatile__ (
"syscall"
: "+r" (rax)
: "r" (rdi), "r" (rsi), "r" (rdx)
: "cc", "rcx", "r11", "memory"
);
return rax;
}
void my_exit(int exit_status) {
register int64_t rax __asm__ ("rax") = 60;
register int rdi __asm__ ("rdi") = exit_status;
__asm__ __volatile__ (
"syscall"
: "+r" (rax)
: "r" (rdi)
: "cc", "rcx", "r11", "memory"
);
}
struct Try1
{
u64 val;
constexpr Try1() { val=0; }
u64 Get() const { return val; }
};
static char buf[1024*8]; //originally mmap but lets reduce code
static __thread u64 sanity_check;
static __thread Try1 t1;
static Try1 global;
extern "C"
int _start()
{
auto tls_size = 4096*2;
auto originalFS = _readfsbase_u64();
_writefsbase_u64((u64)(buf+4096));
global.val = 1;
global.Get(); //Executes fine
sanity_check=6;
t1.val = 7;
my_write(1, "Hello\n", sanity_check);
my_write(1, "Hello2\n", t1.val); //Still fine
my_write(1, "Hello3\n", t1.Get()); //crash! :/
my_exit(0);
return 0;
}
组合:
4010b4: e8 47 ff ff ff call 401000 <_Z8my_writeiPKvm>
4010b9: 64 48 8b 04 25 f8 ff mov rax,QWORD PTR fs:0xfffffffffffffff8
4010c0: ff ff
4010c2: 48 89 c2 mov rdx,rax
4010c5: 48 8d 05 3b 0f 00 00 lea rax,[rip+0xf3b] # 402007 <_ZNK4Try13GetEv+0xeef>
4010cc: 48 89 c6 mov rsi,rax
4010cf: bf 01 00 00 00 mov edi,0x1
4010d4: e8 27 ff ff ff call 401000 <_Z8my_writeiPKvm>
4010d9: 64 48 8b 04 25 00 00 mov rax,QWORD PTR fs:0x0
4010e0: 00 00
4010e2: 48 05 f8 ff ff ff add rax,0xfffffffffffffff8
4010e8: 48 89 c7 mov rdi,rax
4010eb: e8 28 00 00 00 call 401118 <_ZNK4Try13GetEv>
4010f0: 48 89 c2 mov rdx,rax
4010f3: 48 8d 05 15 0f 00 00 lea rax,[rip+0xf15] # 40200f <_ZNK4Try13GetEv+0xef7>
4010fa: 48 89 c6 mov rsi,rax
4010fd: bf 01 00 00 00 mov edi,0x1
401102: e8 f9 fe ff ff call 401000 <_Z8my_writeiPKvm>
401107: bf 00 00 00 00 mov edi,0x0
40110c: e8 12 ff ff ff call 401023 <_Z7my_exiti>
401111: b8 00 00 00 00 mov eax,0x0
401116: c9 leave
401117: c3 ret
【问题讨论】:
-
register是自 C++17 以来未使用的关键字。 -
@FrançoisAndrieux 如果没有它,该程序集似乎无法工作
-
感觉还是直接写汇编比较好。
-
@FrançoisAndrieux 我认为让人们复制/粘贴两个单独的文件不值得费心。它似乎不会影响我的问题
-
@FrançoisAndrieux:
register __asm__是一个 gcc/clang 扩展,与内联汇编一起使用。见gcc.gnu.org/onlinedocs/gcc/…
标签: c++ linux gcc x86-64 thread-local-storage