subl导致浮点异常

时间:2015-06-18 15:12:27

标签: assembly x86

我正在创建一个编译器,它应该将虚构的语言编译成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 $0, %ebx
  movl $1, %eax
  int $0x80

.globl f
.type f, @function
f:
  pushl %ebp 
  movl %esp, %ebp 
  .equ n, 8
  pushl n(%ebp)
  call print_int
  addl $4, %esp

.L1_f:
  movl %ebp, %esp 
  popl %ebp 
  ret

.globl main
.type main, @function
main:
  pushl %ebp 
  movl %esp, %ebp 
  .equ _tmp4, -4
  subl $16, %esp
  movl $1, x
  pushl x
  call f
  movl %eax, _tmp4(%ebp)
  addl $4, %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 $10 # base = 10
    .equ bufsize, -8
    pushl $1 # bufsize = 1 ('\n')
    .equ negative, -12
    pushl $0 # negative = 0
    # stack: .. value return-addr saved-ebp base bufsize
    pushl $10 # push newline to be printed last
    movl value(%ebp), %eax 
        jge .L1 # if value >= 0
    # value < 0: remember
        movl $1, 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 $48, (%esp)
    incl bufsize(%ebp) # ++bufsize
        cmpl $0, %eax
    jne .L1 # loop if value != 0
    # put sign if negative
    cmpl $0, negative(%ebp)
    je .L2
    pushl $45 # '-'
    incl bufsize(%ebp)
.L2:
        # write(2): eax = 4, ebx = fd, ecx = buffer start, edx = buffer size
    movl $4, %eax # code for write syscall
    movl $1, %ebx # fd stdout = 1
    movl %esp, %ecx # buffer start = top of stack
        movl $4, %edx # bufsize * 4 bytes
    imul bufsize(%ebp), %edx 
    int $0x80 # syscall
    movl %ebp, %esp
    popl %ebp # restore saved frame pointer 
    ret

问题是当我尝试使用此命令运行此代码时(它在64位linux mint笔记本电脑上运行):

as --32 simple-2.s -o simple.o && ld -m elf_i386 simple.o -o simple

我得到一个例外,即浮点异常。 当我注释掉行$ 16,%esp时,我的代码按预期运行。 为什么这一行导致异常?

1 个答案:

答案 0 :(得分:0)

subl $16, %esp是一只红鲱鱼。实际问题出在print_int

movl value(%ebp), %eax 
jge .L1 # if value >= 0

movl没有设置标记。您在test %eax, %eax之前错过了jge或同等内容。

学习使用调试器。它会指出你正确的问题。这是我做的:

Program received signal SIGFPE, Arithmetic exception.
print_int () at test.s:28
28          divl base(%ebp)

好的,那为什么会这样呢?让我们看一下eaxedx中的红利:

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

从这里可以很容易地发现问题。