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)

好吧,为什么会这样?让我们看看 eaxedx 的股息:

(gdb) p $eax
 = -1
(gdb) p $edx
 = -1

从这里很容易发现问题。