Gcc 气体组件代码exit()';s与SIGSEGV
我正在玩GAS assembly并链接它,而不使用gcc。相反,我使用作为汇编程序,并链接到ld 我的代码:Gcc 气体组件代码exit()';s与SIGSEGV,gcc,assembly,ld,gnu-assembler,low-level,Gcc,Assembly,Ld,Gnu Assembler,Low Level,我正在玩GAS assembly并链接它,而不使用gcc。相反,我使用作为汇编程序,并链接到ld 我的代码: .section .text .globl _start _start: xorq %rax, %rax movb $60, %al movb $1, %dil int $0x80 我用于组装和链接的命令: as -g -D -o test.o test.S && ld --format elf64-x86-64 -o test te
.section .text
.globl _start
_start:
xorq %rax, %rax
movb $60, %al
movb $1, %dil
int $0x80
我用于组装和链接的命令:
as -g -D -o test.o test.S && ld --format elf64-x86-64 -o test test.o
这是调试之前/之后的gdb:
(gdb) disas _start
Dump of assembler code for function _start:
0x0000000000400078 <+0>: xor %rax,%rax
0x000000000040007b <+3>: mov $0x3c,%al
0x000000000040007d <+5>: mov $0x1,%dil
0x0000000000400080 <+8>: int $0x80
End of assembler dump.
(gdb) b *_start+8
Breakpoint 1 at 0x400080: file test.S, line 7.
(gdb) r
Starting program: /tmp/test
Breakpoint 1, _start () at test.S:7
7 int $0x80
(gdb) i r
rax 0x3c 60
rbx 0x0 0
rcx 0x0 0
rdx 0x0 0
rsi 0x0 0
rdi 0x1 1
rbp 0x0 0x0
rsp 0x7fffffffebc0 0x7fffffffebc0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0x400080 0x400080 <_start+8>
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400082 in ?? ()
(gdb) i r
rax 0x12 18
rbx 0x0 0
rcx 0x0 0
rdx 0x0 0
rsi 0x0 0
rdi 0x1 1
rbp 0x0 0x0
rsp 0x7fffffffebc0 0x7fffffffebc0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0x400082 0x400082
eflags 0x10246 [ PF ZF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) x/x $rip
0x400082: 0x00000000
(gdb) x/x $rip-2
0x400080 <_start+8>: 0x000080cd
您确实应该将
syscall
而不是int$0x80
与64位代码一起使用。问题在于int$0x80
system call使用32位Linux系统调用号。Sysexit是1而不是60。通过int$0x80
进行的32位系统调用可在以下位置找到:。像这样的32位系统调用(即使在64位代码中)也遵循通过ebx、ecx、edx、esi、edi、ebp(按顺序)传递参数的32位约定。但我重申,对于64位代码,请使用syscall
指令,而不是int$0x80
使用syscall修复了问题。尽管如此,unistd_64.h中的exit syscall显示为$60:/usr/include/asm/unistd_64.h:64:#define u NR_exit 60
是,因为int$0x80
是32位系统调用接口,而不是64位系统调用接口。unistd_64.h系统调用应用于syscall
指令,而不是int$0x80
。我在第一条评论的链接中给出了32位系统调用(及其系统调用号)的链接。与64位syscall
寄存器相比,具有int$0x80
的参数也通过不同的寄存器syscall
和int$0x80
具有完全不同的约定和编号。吹毛求疵:as
不是编译器。这是一个汇编程序。因此,你不能用它编译东西,只能组装它们。对不起,你是对的。我知道as的用途,但我用错了它的名字。谢谢你真的应该使用syscall
而不是int$0x80
和64位代码。问题在于int$0x80
system call使用32位Linux系统调用号。Sysexit是1而不是60。通过int$0x80
进行的32位系统调用可在以下位置找到:。像这样的32位系统调用(即使在64位代码中)也遵循通过ebx、ecx、edx、esi、edi、ebp(按顺序)传递参数的32位约定。但我重申,对于64位代码,请使用syscall
指令,而不是int$0x80
使用syscall修复了问题。尽管如此,unistd_64.h中的exit syscall显示为$60:/usr/include/asm/unistd_64.h:64:#define u NR_exit 60
是,因为int$0x80
是32位系统调用接口,而不是64位系统调用接口。unistd_64.h系统调用应用于syscall
指令,而不是int$0x80
。我在第一条评论的链接中给出了32位系统调用(及其系统调用号)的链接。与64位syscall
寄存器相比,具有int$0x80
的参数也通过不同的寄存器syscall
和int$0x80
具有完全不同的约定和编号。吹毛求疵:as
不是编译器。这是一个汇编程序。因此,你不能用它编译东西,只能组装它们。对不起,你是对的。我知道as的用途,但我用错了它的名字。谢谢
$ strace ./test
execve("./test", ["./test"], [/* 18 vars */]) = 0
exit(1) = 18
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x12} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)