我正在尝试模拟一个项目,以便可以测试遍历CG的opt pass,但是我主要受到clang奇怪的编译选择的阻碍,而llvm-link进一步加剧了这种选择。我给你一些代码:
main.c:
#include "xos/xos.h"
int main() {
playXOs();
return 0;
}
xos.h:
#ifndef SLICEREXAMPLEPROJECT_XOS_H
#define SLICEREXAMPLEPROJECT_XOS_H
void playXOs();
#endif // SLICEREXAMPLEPROJECT_XOS_H
我单独编译:
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
store i32 0, i32* %1, align 4
call void(...) @playXOs()
ret i32 0
}
declare dso_local void @playXOs(...) #1
然后链接其他文件:
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
store i32 0, i32* %1, align 4
call void (...) bitcast (void ()* @playXOs to void (...)*)()
ret i32 0
}
在最初的编译中,如果我理解正确,认为playXOs
是一个var arg函数?如果我手动编辑main.ll来更改呼叫站点并转发声明不为playXOs(...)
,则链接的文件中没有奇怪的位广播。有人有解决方案吗?
llvm信息:
clang version 8.0.0 (git@github.com:llvm-mirror/clang.git 8ca7a0dcb7e9a0cd7bf71ff4b70e12462c16f205) (git@github.com:llvm-mirror/llvm.git e9eedd7fa6f4f861afbc7a2862f3f5504e6d340f)
Target: x86_64-unknown-linux-gnu
Thread model: posix
编辑:我忘了提及,这对我来说是个问题,因为尽管我得到的CG包含playXOs
的呼叫站点,但CallGraphNode具有null函数。
答案 0 :(得分:2)
像“ int f()”这样的声明意味着f是一个具有固定数量参数的函数,但是我们不知道有多少个参数。它不是具有可变数量参数的函数。它可能是一个带有0、1、2、3 ...自变量的函数,我们只是不知道哪个。
还要求所有参数的类型(我们不知道)是“通常的提升”结果的类型。因此,实际函数不能为“ int f(float x)”,因为调用f(3.0f)会将3.0f提升为两倍,然后调用将是错误的。
当您实际调用说f(3.0f,(char)1)时,编译器会将3.0f提升为double,将(char)1提升为int,如果实际函数为“ int”,则会生成正确的代码f(double x,int y)”。如果这种猜测是错误的,则您的应用程序可能会崩溃。
当然,如果实际函数是“ int f(void)”,而您调用f()则一切都很好。但是您可以调用f(1),这将是不确定的行为。
答案 1 :(得分:0)
与往常一样,您花了一个或两个小时就完全感到沮丧,放弃并发表在SO上,几秒钟后找到答案。
我将标头声明更改为void playXOs(void)
,以明确地将其声明为没有任何参数,并且可以在不进行任何强制转换或VA猜测的情况下进行编译。
有人能指出我的c规范吗?它说编译器不能假设f()
是f(void)
而不是f(...)
?会接受它作为答案。