我正在创建一个编译器,它应该将虚构的语言编译成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时,我的代码按预期运行。 为什么这一行导致异常?
答案 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)
好的,那为什么会这样呢?让我们看一下eax
和edx
中的红利:
(gdb) p $eax
$1 = -1
(gdb) p $edx
$2 = -1
从这里可以很容易地发现问题。