use*_*143 3 c x86 assembly cygwin x86-64
我目前正在学习本教程,但我不是该学校的学生。
GDB 给了我一个分段错误thread_start
:
movq %rsp, (%rdi) # save sp in old thread's tcb
Run Code Online (Sandbox Code Playgroud)
当我回溯时,这是附加信息:
#0 thread_start () at thread_start.s:16
#1 0x0000000180219e83 in _cygtls::remove(unsigned int)::__PRETTY_FUNCTION__
() from /usr/bin/cygwin1.dll
#2 0x00000000ffffcc6b in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
Run Code Online (Sandbox Code Playgroud)
作为一个新手,我一生都无法弄清楚为什么。这是我的主文件:
#define STACK_SIZE 1024*1024
//Thread TCB
struct thread {
unsigned char * stack_pointer;
void(*initial_function)(void *);
void * initial_argument;
};
struct thread * current_thread;
struct thread * inactive_thread;
void thread_switch(struct thread * old_t, struct thread * new_t);
void thread_start(struct thread * old_t, struct thread * new_t);
void yield() {
//swap threads
struct thread * temp = current_thread;
current_thread = inactive_thread;
inactive_thread = temp;
thread_switch(inactive_thread, current_thread);
}
void thread_wrap() {
// call the thread's function
current_thread->initial_function(current_thread->initial_argument);
yield();
}
int factorial(int n) {
return n == 0 ? 1 : n * factorial(n - 1);
}
// calls and print the factorial
void fun_with_threads(void * arg) {
int n = *(int*)arg;
printf("%d! = %d\n", n, factorial(n));
}
int main() {
//allocate memory for threads
inactive_thread = (struct thread*) malloc(sizeof(struct thread));
current_thread = (struct thread*) malloc(sizeof(struct thread));
// argument for factorial
int *p= (int *) malloc(sizeof(int));
*p = 5;
// intialise thread
current_thread->initial_argument = p;
current_thread->initial_function = fun_with_threads;
current_thread->stack_pointer = ((unsigned char*) malloc(STACK_SIZE)) + STACK_SIZE;
thread_start(inactive_thread, current_thread);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是我的 thread_start 的 asm 代码
# Inline comment
/* Block comment */
# void thread_switch(struct thread * old_t, struct thread * new_t);
.globl thread_start
thread_start:
pushq %rbx # callee-save
pushq %rbp # callee-save
pushq %r12 # callee-save
pushq %r13 # callee-save
pushq %r14 # callee-save
pushq %r15 # callee-save
movq %rsp, (%rdi) # save sp in old thread's tcb
movq (%rsi), %rsp # load sp from new thread
jmp thread_wrap
Run Code Online (Sandbox Code Playgroud)
和线程开关:
# Inline comment
/* Block comment */
# void thread_switch(struct thread * old_t, struct thread * new_t);
.globl thread_switch
thread_switch:
pushq %rbx # callee-save
pushq %rbp # callee-save
pushq %r12 # callee-save
pushq %r13 # callee-save
pushq %r14 # callee-save
pushq %r15 # callee-save
movq %rsp, (%rdi) # save sp in old thread's tcb
movq (%rsi), %rsp # load sp from new thread
popq %r15 # callee-restore
popq %r14 # callee-restore
popq %r13 # callee-restore
popq %r12 # callee-restore
popq %rbp # callee-restore
popq %rbx # callee-restore
ret # return
Run Code Online (Sandbox Code Playgroud)
你在使用 cygwin,对吗?它默认使用 Windows x64 调用约定,而不是 System V x86-64 psABI。所以你的参数不在%rdi
and中%rsi
。
调用约定是Windows x64,但ABI略有不同:long
是64位,所以它是LP64而不是LLP64。请参阅cygwin 文档。
__attribute__((sysv_abi))
您可以使用原型覆盖默认值,但这仅适用于理解 GNU C 的编译器。
Agner Fog 的调用约定指南对如何编写在 Windows 和非 Windows 上汇编为工作函数的源代码提供了一些建议。最直接的就是使用 an#ifdef
来选择不同的函数序言。
此Intel x64 程序集介绍有点以 Windows 为中心,并详细介绍了 Windows x64__fastcall
调用约定。
(后面是示例和内容。这是一个相当大且很好的教程,从非常基本的内容开始,包括如何使用汇编器等工具。我推荐它用于在 Windows 开发环境中学习 x86-64 asm,也许一般来说。)
Windows x64
__fastcall
(与 x64 类似__vectorcall
,但不在向量寄存器中传递向量)
- RCX、RDX、R8、R9按从左到右的顺序用于整数和指针参数
- XMM0、1、2 和 3 用于浮点参数。
- 其他参数从左到右压入堆栈。
- 长度小于 64 位的参数不进行零扩展;高位包含垃圾。
- 调用者有责任在调用函数之前分配 32 字节的“影子空间”(如果需要,用于存储 RCX、RDX、R8 和 R9)。
- 调用者有责任在调用后清理堆栈。
- 如果 64 位或更少,则在 RAX 中返回整数返回值(类似于 x86)。
- 浮点返回值在 XMM0 中返回。
- 较大的返回值(结构)具有由调用者在堆栈上分配的空间,并且当被调用者被调用时,RCX 包含指向返回空间的指针。然后将整数参数的寄存器使用情况向右推一位。RAX 将此地址返回给调用者。
- 堆栈是 16 字节对齐的。“call”指令压入一个 8 字节的返回值,因此所有非叶函数在分配堆栈空间时必须将堆栈调整为 16n+8 形式的值。
- 寄存器 RAX、RCX、RDX、R8、R9、R10 和 R11 被视为易失性寄存器,必须在函数调用时被视为已销毁。RBX、RBP、RDI、RSI、R12、R14、R14 和 R15 必须保存在使用它们的任何函数中。
- 请注意,浮点(以及 MMX)寄存器没有调用约定。
- 更多详细信息(可变参数、异常处理、堆栈展开)请访问 Microsoft 的站点。
链接到x86标签 wiki中的 MS 调用约定文档(以及 System V ABI 文档,以及大量其他好东西)。
另请参阅为什么 Windows64 使用与 x86-64 上的所有其他操作系统不同的调用约定?