【发布时间】:2016-10-31 11:25:11
【问题描述】:
编辑在下面查看我的自我回答
我一直试图在 NASM 中复制这个 C 程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
static void handle(int sig) {
int status;
wait(&status);
}
int main(int argc, char* argv[]) {
struct sigaction act;
bzero(&act, sizeof(act));
act.sa_handler = &handle;
sigaction(SIGCLD, &act, NULL);
pid_t pid;
if ( (pid = fork()) == 0) {
printf("message from child\n");
exit(0);
}
printf("message from parent\n");
pause();
exit(0);
}
我的 NASM 代码如下所示:
USE64
STRUC sigact
.handler resq 1
.mask resq 16
.flag resd 1
.restorer resq 1
.pad resb 4
ENDSTRUC
section .text
global _start
_start:
; register SIGCHLD handler
mov rdi, act
mov rsi, sigact_size
call bzero
mov QWORD [act], handle
; still need to figure out what these mean
; yanked out of gdb right before the same syscall
; and the act struct had these set :\
mov QWORD [act+8], 0x4000000
mov DWORD [act+16], 0xf7a434a0
mov DWORD [act+20], 0x7fff
mov rax, 13
mov rdi, 17
lea rsi, [act]
mov rdx, 0x0
mov r10, 0x8
syscall
cmp rax, 0
jne sigaction_fail
mov rax, 57
syscall
cmp rax, 0
je child
mov rax, parentmsg
call print
mov rax, 34
syscall
mov rax, parentexit
call print
mov rax, 60
mov rdi, 0
syscall
sigaction_fail:
enter 0, 0
mov rax, safailed
call print
mov rax, 60
mov rdi, -1
syscall
handle:
enter 0x10, 0
push rax
push rsi
push rdi
push rdx
push r10
lea rsi, [rbp-0x10]
mov rax, 61
mov rdi, -1
xor rdx, rdx
xor r10, r10
syscall
cmp rax, -1
jne .handle_success
mov rax, hdfailed
call print
mov rax, 60
mov rdi, -1
syscall
.handle_success:
mov rax, hdsuccess
call print
pop r10
pop rdx
pop rdi
pop rsi
pop rax
leave
ret
child:
mov rax, childmsg
call print
mov rax, 60
mov rdi, 0
syscall
; print a null terminated string stored in rax
print:
enter 0, 0
push rbx
push rdx
push rdi
push rsi
mov rbx, rax
call strlen
mov rdx, rax
mov rax, 1
mov rdi, 1 ; stdout
mov rsi, rbx
syscall
pop rsi
pop rdi
pop rdx
pop rbx
leave
ret
bzero:
; rdi pointer to uint8_t
; uint32_t rsi length
enter 0, 0
mov rcx, rsi
dec rcx ; err..
.bzeroloop:
lea rax, [rdi + rcx]
xor rax, rax
cmp rcx, 0
je .bzerodone
dec rcx
jmp .bzeroloop
.bzerodone:
leave
ret
strlen:
enter 0, 0
push rbx
mov rbx, rax
.strlen_countchar:
cmp BYTE [rax], 0 ; compare it to null byte
jz .strlen_exit
inc rax
jmp .strlen_countchar
.strlen_exit:
sub rax, rbx
pop rbx
leave
ret
section .data
childmsg: db "from child", 0xa, 0 ; null terminated
parentmsg db "from parent", 0xa, 0
handlemsg db "in handle", 0xa, 0
safailed db "failed to set signal handler", 0xa, 0
hdfailed db "failed waiting for child", 0xa, 0
hdsuccess db "successfully waited on child", 0xa, 0
parentexit db "parent exiting", 0xa, 0
section .bss
act: resb sigact_size
status: resq 1
发送信号时它成功等待子进程,但返回时立即出现 seg 错误。我已经尝试阅读越来越多的关于信号和信号处理的内容,但在这一点上,所有这些都在我脑海中混杂在一起。抱歉,NASM 代码丑陋或不标准。我不仅在学习,而且我可能每个部分至少重写了 25 次(handle 可能超过 100 次)。
【问题讨论】:
-
你查看了
handle的 gcc 的 asm 输出吗?这是pretty simple。另外,永远不要使用enter指令。它慢得可怕。 (参见 Agner Fog 的指南,链接自 x86 tag wiki。) -
另外,您是否使用调试器查看实际出错的指令,并检查
rsp是否正确(即指向返回地址,就像它在函数入口处一样)
标签: segmentation-fault nasm x86-64