【发布时间】:2021-11-27 19:30:07
【问题描述】:
我找了好几个小时,但在我的代码中找不到错误。该程序似乎在“opadd”标签处退出。我在 Linux 上使用 x86_64,使用 AT&T 语法。
程序将一个字符串作为输入,例如“2 3 add 4 mul”,然后,对于这个特定的示例,应该执行以下操作:
- 将 2 添加到堆栈中
- 将 3 添加到堆栈中
- 计算 2 和 3 的和,然后将 5 添加到堆栈中
- 将 5 和 4 相乘并将 20 添加到堆栈中,然后打印 20。
.data
formatPrintf: .asciz "%d"
sir: .space 1000
delim: .asciz " "
formatScanf: .asciz "%1000[^\n]"
cuvant: .space 100
primulNumar: .space 4
atoiCuvant: .long 0
x: .space 4
y: .space 4
eval: .long 0
op: .space 4
add: .asciz "add"
sub: .asciz "sub"
mul: .asciz "mul"
div: .asciz "div"
.text
.global main
main:
pushl $sir
pushl $formatScanf
call scanf
popl %ebx
popl %ebx
pushl $delim
pushl $sir
call strtok
popl %ebx
popl %ebx
pushl %eax
call atoi
popl primulNumar
movl %eax, primulNumar
pushl primulNumar
et_loop:
pushl $delim
pushl $0
call strtok
popl %ebx
popl %ebx
cmp $0, %eax
je exit
mov %eax, cuvant
pushl %eax
call atoi
popl %ebx
mov %eax, atoiCuvant
cmp $0, atoiCuvant
je operatie
pushl %eax
jmp et_loop
operatie:
push $cuvant
push $add
call strcmp
popl %ebx
popl %ebx
cmp $0, %eax
je opadd
push $cuvant
push $sub
call strcmp
popl %ebx
popl %ebx
cmp $0, %eax
je opsub
push $cuvant
push $mul
call strcmp
popl %ebx
popl %ebx
cmp $0, %eax
je opmul
push $cuvant
push $div
call strcmp
popl %ebx
popl %ebx
cmp $0, %eax
je opdiv
opadd:
popl %edx
popl y
add %edx, y
push y
jmp et_loop
opmul:
popl %eax
popl %ebx
mul %ebx
pushl %eax
jmp et_loop
opdiv:
popl %eax
popl %ebx
div %ebx
pushl %eax
jmp et_loop
opsub:
popl %eax
popl y
sub %eax,y
pushl y
jmp et_loop
exit:
popl eval
pushl eval
pushl $formatPrintf
call printf
popl %ebx
popl %ebx
pushl $0
call fflush
popl %ebx
movl $1, %eax
xorl %ebx, %ebx
int $0x80
编辑:
.data
formatPrintf: .asciz "%d"
sir: .space 1000
delim: .asciz " "
formatScanf: .asciz "%1000[^\n]"
cuvant: .space 100
primulNumar: .space 4
atoiCuvant: .space 4
x: .space 4
y: .long 4
eval: .space 4
op: .space 4
add: .asciz "a"
sub: .asciz "s"
mul: .asciz "m"
div: .asciz "d"
.text
.global main
main:
pushl $sir
pushl $formatScanf
call scanf
popl %ebx
popl %ebx
pushl $delim
pushl $sir
call strtok
popl %ebx
popl %ebx
pushl %eax
call atoi
popl %ebx
movl %eax, primulNumar
pushl primulNumar
et_loop:
pushl $delim
pushl $0
call strtok
popl %ebx
popl %ebx
cmp $0, %eax
je exit
mov %eax, %esi
pushl %eax
call atoi
popl %ebx
cmp $0, %eax
je operatie
pushl %eax
jmp et_loop
operatie:
mov $0, %ecx
movb (%esi,%ecx,1), %al
cmp $97,%al
je opadd
cmp $115, %al
je opsub
cmp $109, %al
je opmul
cmp $100, %al
je opdiv
opadd:
popl %ebx
popl %eax
add %ebx, %eax
pushl %eax
jmp et_loop
opmul:
popl %eax
popl %ebx
mul %ebx
pushl %eax
jmp et_loop
opdiv:
popl %ebx
popl %eax
xorl %edx, %edx
div %ebx
pushl %eax
jmp et_loop
opsub:
popl %eax
popl y
sub %eax,y
pushl y
jmp et_loop
exit:
popl eval
pushl eval
pushl $formatPrintf
call printf
popl %ebx
popl %ebx
pushl $0
call fflush
popl %ebx
movl $1, %eax
xorl %ebx, %ebx
int $0x80
【问题讨论】:
-
您是否尝试过使用 valgrind 等内存检查器?类似的东西应该可以帮助您确定问题出现在哪一行。
-
@user1280483 谢谢,我使用了 gdb,看起来程序在“opadd”标签处退出。我还是不知道怎么解决这个问题
-
opadd是一个标签。它在哪个指令上产生段错误? -
@JosephSible-ReinstateMonica 如果我在
operatie放置一个断点,在两个stepi之后,gdb 转到??() from /lib32/libc.so.6,我认为是strcmp,然后它以信号 SIGSEGV -
这是 32 位代码;我假设您正在使用
gcc -m32 foo.s构建它。所有这些推送和弹出是怎么回事?你调用strtok,然后你通过将任何垃圾弹出到EAX中来重新平衡堆栈,覆盖返回值。然后通过推动 EAX 将其传递给 atoi!也许你很幸运,strtok没有碰巧覆盖它的堆栈参数,而且你只在第一次调用而不是在循环中这样做,所以你得到了你传递的原始字符串,它恰好是第一个的开始令牌?