subl 导致浮点数异常
subl causing Floating point exception
我正在创建一个编译器,它将一种虚构的语言编译成 asm x86 代码。
编译这段代码时(虚构的代码):
int x;
int f(int n) {
write n;
}
int main() {
x = 1;
f(x);
}
write 等同于在控制台打印。
期望的输出是:1
这导致此汇编代码:
.section .text
.include "print_int.s"
.globl _start
.type _start, @function
_start:
call main
movl [=11=], %ebx
movl , %eax
int [=11=]x80
.globl f
.type f, @function
f:
pushl %ebp
movl %esp, %ebp
.equ n, 8
pushl n(%ebp)
call print_int
addl , %esp
.L1_f:
movl %ebp, %esp
popl %ebp
ret
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
.equ _tmp4, -4
subl , %esp
movl , x
pushl x
call f
movl %eax, _tmp4(%ebp)
addl , %esp
.L3_main:
movl %ebp, %esp
popl %ebp
ret
.section .data
x: .int 1
print_int函数:
# print an integer
.section .text
.globl print_int
.type print_int, @function
# print_it(int value) -- print value followed by \n to stdout.
print_int:
pushl %ebp
movl %esp, %ebp
.equ value, 8 # parameter offset
# initialize local variables:
.equ base, -4
pushl # base = 10
.equ bufsize, -8
pushl # bufsize = 1 ('\n')
.equ negative, -12
pushl [=12=] # negative = 0
# stack: .. value return-addr saved-ebp base bufsize
pushl # push newline to be printed last
movl value(%ebp), %eax
jge .L1 # if value >= 0
# value < 0: remember
movl , negative(%ebp)
negl %eax # value = -value
.L1:
cdq # setup %edx:%eax for division
# aex = value/base, edx = value % base
divl base(%ebp)
# push remainder digit
pushl %edx
addl , (%esp)
incl bufsize(%ebp) # ++bufsize
cmpl [=12=], %eax
jne .L1 # loop if value != 0
# put sign if negative
cmpl [=12=], negative(%ebp)
je .L2
pushl # '-'
incl bufsize(%ebp)
.L2:
# write(2): eax = 4, ebx = fd, ecx = buffer start, edx = buffer size
movl , %eax # code for write syscall
movl , %ebx # fd stdout = 1
movl %esp, %ecx # buffer start = top of stack
movl , %edx # bufsize * 4 bytes
imul bufsize(%ebp), %edx
int [=12=]x80 # syscall
movl %ebp, %esp
popl %ebp # restore saved frame pointer
ret
问题是当我尝试使用此命令 运行 此代码时(在 64 位 linux mint 笔记本电脑上 运行s):
as --32 simple-2.s -o simple.o && ld -m elf_i386 simple.o -o simple
我遇到一个异常,即浮点异常。
当我按预期注释掉 subl $16, %esp 行时,我的代码 运行s 。
为什么此行会导致异常?
subl , %esp
是一条红鲱鱼。实际问题在 print_int
:
movl value(%ebp), %eax
jge .L1 # if value >= 0
movl
不设置标志。您在 jge
.
之前缺少 test %eax, %eax
或等效项
学习使用调试器。它会指出你正确的问题。这是我所做的:
Program received signal SIGFPE, Arithmetic exception.
print_int () at test.s:28
28 divl base(%ebp)
好吧,为什么会这样?让我们看看 eax
和 edx
的股息:
(gdb) p $eax
= -1
(gdb) p $edx
= -1
从这里很容易发现问题。
我正在创建一个编译器,它将一种虚构的语言编译成 asm x86 代码。
编译这段代码时(虚构的代码):
int x;
int f(int n) {
write n;
}
int main() {
x = 1;
f(x);
}
write 等同于在控制台打印。
期望的输出是:1
这导致此汇编代码:
.section .text
.include "print_int.s"
.globl _start
.type _start, @function
_start:
call main
movl [=11=], %ebx
movl , %eax
int [=11=]x80
.globl f
.type f, @function
f:
pushl %ebp
movl %esp, %ebp
.equ n, 8
pushl n(%ebp)
call print_int
addl , %esp
.L1_f:
movl %ebp, %esp
popl %ebp
ret
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
.equ _tmp4, -4
subl , %esp
movl , x
pushl x
call f
movl %eax, _tmp4(%ebp)
addl , %esp
.L3_main:
movl %ebp, %esp
popl %ebp
ret
.section .data
x: .int 1
print_int函数:
# print an integer
.section .text
.globl print_int
.type print_int, @function
# print_it(int value) -- print value followed by \n to stdout.
print_int:
pushl %ebp
movl %esp, %ebp
.equ value, 8 # parameter offset
# initialize local variables:
.equ base, -4
pushl # base = 10
.equ bufsize, -8
pushl # bufsize = 1 ('\n')
.equ negative, -12
pushl [=12=] # negative = 0
# stack: .. value return-addr saved-ebp base bufsize
pushl # push newline to be printed last
movl value(%ebp), %eax
jge .L1 # if value >= 0
# value < 0: remember
movl , negative(%ebp)
negl %eax # value = -value
.L1:
cdq # setup %edx:%eax for division
# aex = value/base, edx = value % base
divl base(%ebp)
# push remainder digit
pushl %edx
addl , (%esp)
incl bufsize(%ebp) # ++bufsize
cmpl [=12=], %eax
jne .L1 # loop if value != 0
# put sign if negative
cmpl [=12=], negative(%ebp)
je .L2
pushl # '-'
incl bufsize(%ebp)
.L2:
# write(2): eax = 4, ebx = fd, ecx = buffer start, edx = buffer size
movl , %eax # code for write syscall
movl , %ebx # fd stdout = 1
movl %esp, %ecx # buffer start = top of stack
movl , %edx # bufsize * 4 bytes
imul bufsize(%ebp), %edx
int [=12=]x80 # syscall
movl %ebp, %esp
popl %ebp # restore saved frame pointer
ret
问题是当我尝试使用此命令 运行 此代码时(在 64 位 linux mint 笔记本电脑上 运行s):
as --32 simple-2.s -o simple.o && ld -m elf_i386 simple.o -o simple
我遇到一个异常,即浮点异常。 当我按预期注释掉 subl $16, %esp 行时,我的代码 运行s 。 为什么此行会导致异常?
subl , %esp
是一条红鲱鱼。实际问题在 print_int
:
movl value(%ebp), %eax
jge .L1 # if value >= 0
movl
不设置标志。您在 jge
.
test %eax, %eax
或等效项
学习使用调试器。它会指出你正确的问题。这是我所做的:
Program received signal SIGFPE, Arithmetic exception.
print_int () at test.s:28
28 divl base(%ebp)
好吧,为什么会这样?让我们看看 eax
和 edx
的股息:
(gdb) p $eax
= -1
(gdb) p $edx
= -1
从这里很容易发现问题。