我正在编写一个基本的编译器,并且生成的代码无法按预期工作。
我使用的是朴素的图形着色算法,以根据变量的活跃度在寄存器中分配变量。
问题在于,生成的汇编代码看起来非常好,但是在某些时候,它会产生未定义的行为。
如果我只是使用堆栈而不是使用寄存器存储变量,那么一切正常。
我还发现我无法在%edx
指令周围使用imull
寄存器,并且我想知道%ebx
和%ecx
是否现在正在发生类似的事情。
我使用gcc -m32 "test.s" runtime.c -o test
编译代码,其中runtime.c
是包含打印和输入功能的帮助程序C文件。
我还尝试删除了程序的某些部分(除最后一张以外的所有图片),然后最后一张可以使用。
如果我在上次调用之前调用一个打印功能,它将无法正常工作。
runtime.c
文件:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
int input() {
int num;
char term;
scanf("%d%c", &num, &term);
return num;
}
void print_int_nl(int i) {
printf("%d\n", i);
}
源文件:
a = 10
b = input()
c = - 10
d = -input()
print a
print b
print c
print d
生成的汇编代码: https://pastebin.com/ChSRbWgt
编译.s文件并使用控制台(./test
)运行后,它要求2个输入(按预期)。
我给它1和2。
然后输出是:
10
1
-10
1415880
代替
10
1
-10
-2
答案 0 :(得分:2)
您需要遵守调用约定(例如,Calling conventions for different C++ compilers and operating systems by Agner Fog)。
即,在C编译器的约定中有调用方保存和被调用方保存的寄存器。
您生成的代码需要保留被调用方保存的寄存器,以便能够返回其C调用方。
类似地,printf()将保留被调用者保存的寄存器,但是它会废弃调用者保存的寄存器,这意味着,如果生成的代码调用printf(),则将需要在整个调用中保留调用者保存的寄存器。到printf()或任何其他C函数。
答案 1 :(得分:1)
您需要在第一次输入后清除输入缓冲区,但该缓冲区仍包含换行符,我建议您这样做:
int input() {
int num;
char term;
scanf("%d %c", &num, &term);
return num;
}