llvm-ir - Crystal-lang:如果由 Crystal 或 clang 生成,为什么 LLVM “hello.bc”不一样?
问题描述
这是我的第一个 Stackoverflow 问题 :-)
我的背景:
- 2年Python经验
- 2 个月的 Crystal-lang 经验(使用 Amber 框架运行的网站)
- 1 个月进入 C、C++、汇编
事实: - crystal-lang 正在编译和运行没有任何问题 - 在 x86_64 上运行
请善待,因为我还没有太多低级语言知识。
据我了解,当我们使用 LLVM 编译和运行一个基本的 hello.c 文件时,它如下所示:
你好ç :
#include
int main() {
printf("hello world\n");
return 0;
}
壳 :
$ clang -O3 -emit-llvm hello.c -c -o hello.bc
$ llc hello.bc -o hello.s
$ gcc hello.s -o hello.native
$ ./hello.native
这来自 LLVM 示例)
我的观点是,我们可以生成一个非常短的 hello.bc 文件(128 行),它可以使用以下命令以较慢的方式运行:
$ lli hello.bc
但是当我尝试从 hello.cr 文件生成类似的 hello.bc 并像使用 hello.c 文件一样运行它时:
你好.cr:
puts "hello world"
壳 :
$ crystal build hello.cr --emit llvm-bc --release
$ llc hello.bc -o hello.s
我注意到了什么:
- 这个 hello.bc 文件比从 c 文件生成的文件大得多(43'624 行)
这个 hello.bc 不能使用“lli”运行,因为它会生成:
“LLVM 错误:程序使用了无法解析的外部函数‘pcre_malloc’!
我什至无法从 hello.s 编译为 hello.native
- 如果我尝试使用生成和 hello.ll 文件,同样的问题
据我了解,LLVM 是可移植的,并且所有前端语言都会生成一个中间 *.bc,然后可以将其编译为任何架构。
我的问题是:
- 为什么 hello.bc 在这两种情况下都不相似?
- 我在水晶程序中做错了吗?
谢谢!
解决方案
一切都像它应该的那样。Crystal 有一个运行时库,即使您没有包含任何内容,它也始终存在。这是运行 Crystal 程序所必需的。
C 示例几乎不包含任何其他内容,只是对printf
. 这就是编译后的 ASM 也非常小的原因。
Crystal 的简单puts
调用背后有更多内容。它基于用于处理异步 IO、并发、信号处理、垃圾收集等的库。其中一些库完全在 Crystal 标准库中实现,一些使用直接嵌入到二进制文件中的其他库 ( libgc
) 或仍然需要来自系统的动态库 ( libpcre
, libpthread
)。
默认情况下,任何 Crystal 程序都带有此运行时库。甚至是一个空程序。这通常完全被忽视,因为更大的程序最终还是需要这些东西,并且运行时库的编译二进制大小小于 500 KB(在发布模式下)。像你这样的小程序并不真正需要所有这些来打印一个字符串。但是 Crystal 运行时需要这些库。
注意:您可以在没有这些默认库的情况下编译 Crystal 程序。但这意味着您不能使用Crystal 标准库中的任何内容,并且您必须使用 Crystal 语法编写 C 代码(或实现您自己的标准库):
require "lib_c"
require "c/stdio"
LibC.printf pointerof("hello world".@c)
这可以使用--prelude=empty
选项编译,它会生成一个小得多的 ASM,大致类似于 C 示例。
推荐阅读
- r - 为 r 包提供贡献要求的标准方式?
- java - 无法从 PgBouncer 打开连接(连接尝试超时)
- python - 如何在 Python 中修复超出范围的动态列表索引
- c# - 即使我添加 AllowLoadLocalInfile,此 MySQL 版本也不允许使用的命令
- wpf - 在非 UI 线程上运行并串行运行的多个任务(非并行)
- maven - 如何为依赖项/插件生成属性版本?
- ios - 如何在具有多个部分的 TableView 中使用 searchBar?
- python - 列出此斐波那契代码中的索引超出范围错误
- sql - 如何在Oracle中通过分隔符拆分查询数据?
- javascript - Webpack : 导入 CSS