【发布时间】:2019-04-06 08:13:28
【问题描述】:
我正在编写一个基本编译器,但生成的代码无法按预期工作。
我正在使用一种简单的图形着色算法来根据它们的活跃度在寄存器中分配变量。
问题是生成的汇编代码看起来非常好,但在某些时候,它会产生未定义的行为。
如果我不使用寄存器来存储变量,而是使用堆栈,那么一切正常。
我还发现我不能在imull 指令周围使用%edx 寄存器,我想知道%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
【问题讨论】:
-
您生成的代码可能没有保留调用约定说应该保留的寄存器。 AFAIR,如果你保留除
eax和edx之外的所有内容,你应该没问题。有关更多详细信息,请参见例如Calling conventions for different C++ compilers and operating systems by Agner Fog. -
通过阅读寄存器使用部分,似乎只有
%ebx需要保留(被调用者保存),我确实保留了它。但是,如果我错了,请纠正我,似乎我还应该保留%eax和%edx,因为它们可能会收到一些指令的返回值(即%edx在使用imull时被替换) -
@AlexeyFrunze 1. C != C++。 2. 编译器知道要保存什么。它经过数百万开发人员的测试
-
@P__J__:OP 正在编写自己的编译器,这可能会出错。不过,这不是 minimal reproducible example,因为它们没有显示生成的 asm。
-
@P__J__ 但我正在编写自己的编译器,所以可能我错过了一些阻止它工作的东西