多次调用打印功能后出现未定义的行为

时间:2019-04-06 08:13:29

标签: c assembly

我正在编写一个基本的编译器,并且生成的代码无法按预期工作。
我使用的是朴素的图形着色算法,以根据变量的活跃度在寄存器中分配变量。
问题在于,生成的汇编代码看起来非常好,但是在某些时候,它会产生未定义的行为。

如果我只是使用堆栈而不是使用寄存器存储变量,那么一切正常。
我还发现我无法在%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

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;
}