![](/img/trans.png)
[英]x86 Assembly: Segmentation Fault (Core dumped) while trying to reverse print array
[英]Segmentation fault (core dumped) in x86 assembly
我编写了一个 x86 (IA-32) 汇编程序,它应该从标准输入中读取一个字符串,但无法理解为什么会导致 SEGFAULT。
我使用 GNU 汇编程序使用以下标志组装了这个程序:
$ gcc (flags used) (file_name)
下面是程序的代码:
.text
.globl _start
MAX_CHAR=30
_start:
## Start message ##
movl $4, %eax
movl $1, %ebx
movl $msg, %ecx
movl $len, %edx
int $0x80
## READ ##
movl $3, %eax #sys_read (number 3)
movl $0, %ebx #stdin (number 0)
movl %esp, %ecx #starting point
movl $MAX_CHAR, %edx #max input
int $0x80 #call
## Need the cycle to count input length ##
movl $1, %ecx #counter
end_input:
xor %ebx, %ebx
mov (%esp), %ebx
add $1, %esp #get next char to compare
add $1, %ecx #counter+=1
cmp $0xa, %ebx #compare with "\n"
jne end_input #if not, continue
## WRITE ##
sub %ecx, %esp #start from the first input char
movl $4, %eax #sys_write (number 4)
movl $1, %ebx #stdout (number 1)
movl %ecx, %edx #start pointer
movl %esp, %ecx #length
int $0x80 #call
## EXIT ##
movl $1, %eax
int $0x80
.data
msg: .ascii "Insert an input:\n"
len =.-msg
是什么导致了 SEGFAULT?
欢迎任何帮助。
我看到的错误:
堆栈管理。 您不能假设程序入口时堆栈中已有的数据,也不能假设有多少可用空间。 而且你不能在%esp
的当前地址下面写; 例如,信号处理程序可以随时意外地覆盖它。 所以你需要从%esp
中减去为你的缓冲区分配空间,然后在完成后加回去。
此外, %esp
应始终保持 4 字节对齐。 这不是严格的架构要求,但打破这个规则会导致执行效率低下和很多混乱。 因此,要为 30 字节缓冲区创建空间,请向上取整并从%esp
中减去 32。
当你想调用C写的函数时,还有额外的alignment要求,见gcc x86-32 stack alignment和calling printf 。
由于上述两个原因,不要在循环中使用%esp
作为指针变量:不要管它,选择其他寄存器。
操作数大小。 x86-32 指令通常可以在 8、16 或 32 位上运行。 l
后缀和/或 32 位寄存器(eax、ebx 等)的使用表示 32 位指令。 所以mov (%esp), %ebx
从 memory 加载 4 个字节,并且cmp $0xa, %ebx
将它们与 32 位值0x0000000a
进行比较。 因此,比较将是错误的,除非 memory 中接下来的三个字节恰好全为零。 要获得 8 位操作,请使用 8 位寄存器(al、bl、ah、bh 等),但要注意它们与相应的 16 位和 32 位寄存器重叠; 所以不要尝试同时使用%ebx
和%bl
做不同的事情。 试试movb (%reg), %bl
(如上所述, %reg
不应该是%esp
而是你使用的任何寄存器)和cmpb $0xa, %bl
。 b
后缀是可选的,因为大小是从 8 位bl
寄存器推断出来的,但是由于您在 cod 的大部分 rest 中使用后缀,所以最好保持一致。)
您在这里编写的是 32 位代码,所以一定要在 32 位模式下构建您的程序。 例如,如果使用 gcc,则需要-m32
标志。 从长远来看,您可能更愿意学习 64 位 x86 汇编; 32 位 x86 代码几乎已过时。
实际上,首先通过搜索换行符 (0xa) 来计算输入的长度并不合适。 如果输入根本不包含换行符(如果该行的长度超过 30 个字节,这是可能的),那么您的循环将从缓冲区的末尾运行。 要找出读取了多少个字符,您应该使用read
的返回值,它在 read 系统调用返回后留在%eax
中。 (如果为零,则到达文件末尾;如果为负,则出现错误。)
此外,如果您以默认模式从终端读取,通常您一次最多只能读取一行,因此如果有\n
它将对应于read
返回的输入的末尾。 (但如果标准输入是从文件重定向的,则这不适用。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.