函数在可执行文件中的位置

时间:2013-01-01 20:12:25

标签: c compiler-construction linker

C标准中是否要求编译(和链接)二进制文件中的函数将以有序的形式出现在C文件中?

  

请假设在下面的示例中,编译器没有删除/内联任何函数,它们都存在于二进制文件中。问题不在于编译器可能对空函数做什么,而是关于函数的顺序。

例如,如果我编译example.c:

void bar() {  }
void foo() {  bar();  }
int main() {   foo();  }

我可以确定foo会在输出文件中bar之后出现吗?

4 个答案:

答案 0 :(得分:5)

不,C标准没有这样的要求。在编译和链接方面,仅明确提及函数的特定属性,例如外部或静态链接等,但即使这些也以与实现无关的方式进行描述。到目前为止,在任何标准文档中都没有任何条款(据我所知),它强加了对可执行文件中符号顺序的期望。

答案 1 :(得分:2)

这种语言没有规则。通常,它们确实按照您期望的顺序查看代码,但没有任何说法编译器无法构建一堆函数,并以完全相反的顺序输出它们 - 当然,这是一个未被调用的函数可以删除,类似地,内联函数和编译器可以确定它不需要外部引用可以以其原始形式删除。

您可以通过char *ptr = (char *)bar;找到某个功能的位置。

编辑:注意,通过获取函数的地址,您可以更改函数的内联,因此不要指望这是确定编译器在“正常情况下”执行的操作的好方法。

答案 2 :(得分:0)

没有这样的要求。但是,在您的示例中,如果bar()位于foo()之后,则foo会将bar()视为尚未定义的返回整数的函数。

答案 3 :(得分:0)

无法通过编译器开关单独控制。你需要一个两步的过程;这里为ELF(UN * X目标文件格式)说明了这一点,但对于Windows PE对象可以这样做。

  1. 指示编译器为必须严格控制其代码放置的函数生成单独/特定的目标文件ELF Sections。这可以在GCC中通过function attributescommand line switches完成 根据您希望实现的放置类型,GCC的某些功能属性(hotcold,...)可能已经满足您的需求,但如果没有,则具体订购/具体位置是绝对必要的,然后......
  2. 指示链接器以特定方式对输入部分进行排序/重新排列/合并/定位到输出中。
  3. 实际的代码/数据放置发生在链接时间 - 链接器可以控制对象代码放置“构成对象” - 源对象的ELF部分 - 在生成的目标“复合对象”中,即生成的可执行文件/库。这通过链接描述文件发生。如果使用自定义链接描述文件指示这样做,链接器会将用户指定位置/用户指定顺序的输入节放入输出对象。请参阅GNU binutils (ld) manual有关链接描述文件。

    结果(反映链接器实际放置输入的各个部分的输出位置),您可以请求生成Linker Mapfile;如果您使用非默认/自定义链接描述文件来严格控制代码放置,那么您应该指示链接器执行此操作,以便您可以交叉检查它是否符合您的要求。否则,如果您使用了链接器的默认设置,那么mapfile会告诉您在没有特定覆盖的情况下完成了什么 - 可能是您想要的,也可能不是,但它至少是一种检查方式。