在C或C ++链接器中是否有任何类型检查?
我正确地说连接器没有进行function参数检查。 它们不检查函数调用的数量或类型,也不检查全局数据引用的类型。 这对所有连接体都是如此吗?
我在x86-64上使用Clang定位Linux。 链接器是否检查引用是否在正确的段中? 或者就链接器而言,外部引用实际上只是一个void *?
我来自高级语言背景C#和Scala,所以对于那些沉浸在低级别世界中的人来说,这似乎是显而易见的。 我在汇编程序中写了几个函数(系统调用),我注意到汇编程序中没有外部函数的参数原型。
上下文:我实际上是在编写一个编译器。 目前我的目标是使用汇编程序函数进行系统调用的预处理C .i文件,但替代方案是C ++,汇编程序甚至机器代码,所以我试图权衡成本和收益,特别是类型检查,汇编器/编译器/ 链接器我可以用来检查我自己的程序及其函数原型生成的正确性。
正如@Yakk所解释的那样,函数可以根据它们的参数进行重载,因此编译器会生成包含参数及其类型信息的错位函数名。 链接器主要只检查符号名称和大小,但由于重整确保函数的名称不同,不匹配的参数将不会链接。
函数返回类型不是修改的一部分(因为返回类型上的重载是不合法的),所以如果在一个转换单元中声明int test()
在另一个转换单元中调用float test()
,链接器将不会捕获它,你会得到不好的结果。
类似地,链接器不检查全局变量的类型(以及类的静态成员等),因此如果声明extern int test;
在一个翻译单元中定义float test;
在另一个方面,你会得到不好的结果。
在某些情况下,链接器可以比较两个不同转换单元中的符号大小 ,并且可以以这种方式捕获一些问题。
实际上,这在普通的C ++开发中很少成为问题,因为只要> 1翻译单元需要一个函数或变量或类,你就会在一个包含在两个翻译单元中的头文件中声明它,并且编译器会捕获它链接器甚至运行之前的任何错误。 (如果您使用的是外部二进制库,并且您拥有的头文件与库不匹配,则可能存在问题的一个实例。)
在c ++中,所有编译器都实现了某种forms的名称修改来分隔重载函数; 但是由于返回类型不包含在mangle中(通常),无论如何都可能存在相同的问题。
在C中你是对的 – 链接器无法检查,但这并不像你想象的那么严重。 请记住,编译器已经检查过对函数的调用是否与提供的头匹配,因此导致问题的唯一方法是将头文件的不同重复版本编译成两个不同的c文件,这些文件稍后被链接。
这有点难以做到(尽管如果你管理你可能最终会出现一些非常微妙的错误)。
许多链接器包含提供某种级别的类型检查的function,但细节有所不同。 一些编译器将使用带有下划线的一个调用约定的函数的名称作为前缀,但是省略使用不同调用约定的函数名称的下划线; 如果一个翻译单元使用一个约定声明一个函数,但实际函数是使用另一个约定定的,则该程序将在链接时被拒绝。
某些平台(例如用于PIC的HiTech C)允许编译器或汇编语言程序在声明或引用符号时指定16位值,如果参考点提供的值与不匹配的值,则会发出尖叫声定义。 C编译器基于参数类型和返回类型的组合为每个函数生成散列值,并且如果尝试调用其定义和散列值在定义和调用站点处不同的函数,则链接器将发出尖叫声。