我编写了一个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?
任何帮助都是受欢迎的。
1条答案
按热度按时间sqougxex1#
我看到的错误:
%esp
中当前地址的下面;例如,信号处理程序可以在任何时候意外地覆盖它。2所以你需要从%esp
中减去,为你的缓冲区分配空间,然后在完成后加回来。%esp
应该始终保持4字节对齐。这不是严格的体系结构要求,但违反此规则将导致低效执行和大量混乱。因此,要为30字节缓冲区创建空间,请向上舍入并从%esp
中减去32。当你想调用用C编写的函数时,还有额外的对齐要求,参见gcc x86-32 stack alignment and calling printf。
%esp
作为指针变量:不要管它,选择其他寄存器。l
后缀和/或使用32位寄存器(eax、ebx等)发出32位指令的信号,因此mov (%esp), %ebx
从内存中加载4个字节,和cmp $0xa, %ebx
将它们与32位值0x0000000a
进行比较。因此,除非存储器中的下三个字节恰好都为零,否则比较将是错误的。要获得8位操作,请使用8位寄存器(a1、b1、ah、bh等),但要注意它们与相应的16位和32位寄存器重叠;所以不要尝试同时使用%ebx
和%bl
来做不同的事情。(如上所述,%reg
不应是%esp
,而应是您使用的任何寄存器)和cmpb $0xa, %bl
。b
后缀是可选的,因为其大小是从8位bl
寄存器推断出来的,但由于你在代码的其余部分都使用后缀,所以最好保持一致。)-m32
标志。从长远来看,你可能更愿意学习64位x86汇编; 32位x86代码已经过时了。read
的返回值,在read系统调用返回之后,它被留在%eax
中。(如果它是零,则到达文件结尾;如果为负数,则存在错误。)此外,如果在默认模式下从终端阅读,通常一次最多只能读取一行,因此如果存在
\n
,它将对应于read
返回的输入的结尾(但如果标准输入是从文件重定向的,则这不适用)。