测量使用Clang / LLVM生成的函数的大小?

克里斯蒂娜·布鲁克斯(Kristina Brooks)

最近,在进行项目工作时,我需要测量C函数的大小,以便能够将其复制到其他地方,但是却找不到任何“干净的”解决方案(最终,我只是想拥有一个我可以引用的函数末尾插入的标签)。

为该架构编写了LLVM后端(虽然看上去像ARM,但不是),并且知道它发出了该架构的汇编代码,所以我选择了以下技巧(我认为注释很好地说明了这一点):

/***************************************************************************
 * if ENABLE_SDRAM_CALLGATE is enabled, this function should NEVER be called
 * from C code as it will corrupt the stack pointer, since it returns before
 * its epilog. this is done because clang does not provide a way to get the
 * size of the function so we insert a label with inline asm to measure the
 * function. in addition to that, it should not call any non-forceinlined
 * functions to avoid generating a PC relative branch (which would fail if
 * the function has been copied)
 **************************************************************************/
void sdram_init_late(sdram_param_t* P) {
    /* ... */
#ifdef ENABLE_SDRAM_CALLGATE
    asm(
        "b lr\n"
        ".globl sdram_init_late_END\n"
        "sdram_init_late_END:"
    );
#endif
}

它可以按需工作,但是需要一些汇编程序粘合代码才能调用它,并且这是一个非常肮脏的技巧,它只能起作用,因为我可以假设有关代码生成过程的几件事。

我还考虑了其​​他方法,如果LLVM发出机器代码,这种方法会更好(因为一旦向LLVM后端添加MC发射器,这种方法就会失效)。我考虑的方法涉及采取函数并搜索终止符指令(可能是b lr指令或的变体pop ..., lr),但这也可能带来其他复杂性(尽管它似乎比我最初的解决方案要好)。

谁能建议一种更干净的方法来获得C函数的大小,而不必诉诸于上面概述的丑陋而又不可靠的黑客程序?

彼得·科德斯

我认为您是对的,没有任何真正可移植的方式来执行此操作。允许编译器对函数进行重新排序,因此以源顺序获取下一个函数的地址并不安全(但在某些情况下确实可行)。


如果您可以解析目标文件(也许使用libbfd),则可以从中获取函数的大小。

clang的asm输出具有此元数据(.size每个函数后汇编器指令),但是我不确定它是否最终出现在目标文件中。

int foo(int a) { return a * a * 2; }

   ## clang-3.8 -O3 for amd64:
   ## some debug-info lines manually removed
    .globl  foo
foo:
.Lfunc_begin0:
        .cfi_startproc
        imul    edi, edi
        lea     eax, [rdi + rdi]
        ret
.Lfunc_end0:
        .size   foo, .Lfunc_end0-foo   ####### This line

编译这一个.oclang-3.8 -O3 -Wall -Wextra func-size.c -c,我可以再做:

$ readelf --symbols func-size.o 

Symbol table '.symtab' contains 4 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS func-size.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000000000     7 FUNC    GLOBAL DEFAULT    2 foo   ### This line

这三个指令共7个字节,与size这里输出相匹配它不包含用于对齐入口点的填充或下一个函数:.align指令位于两个标签的相加处,两个标签相减后得出.size

这对于剥离的可执行文件可能效果不佳。即使它们的全局功能也不会出现在可执行文件的符号表中。因此,您可能需要两步构建过程:

  • 编译您的“正常”代码
  • 使用以下命令将您关心的功能的大小存储到表中 readelf | some text processing > sizes.c
  • 编译sizes.c
  • 将所有内容链接在一起

警告

一个真正聪明的编译器可以编译多个相似的函数以共享一个公共实现。因此,一个功能跳入另一个功能主体的中间。如果幸运的话,所有功能都组合在一起,每个功能的“大小”从其入口点一直到其使用的代码块的末尾。(但是这种重叠会使总大小加起来超过文件的大小。)

当前的编译器不执行此操作,但是可以通过将函数放在单独的编译单元中,而不使用整个程序的链接时优化来防止此情况

编译器可以决定将条件执行的代码块放在函数入口之前,因此分支可以为较小的位移使用较短的编码。这使该块看起来像一个静态的“ helper”函数,可能不会包含在该函数的“ size”计算中。不过,当前的编译器也从未这样做。


我不确定的另一个想法很安全

把一个asm volatile刚才在你的函数的最后一个标签定义,然后承担的功能尺寸最大的是+ 32字节或东西。因此,当您复制函数时,您分配的缓冲区32B大于“已计算”的大小。希望标签之外只有一个“ ret” insn,但实际上它可能在函数结尾之前,该函数弹出所有它使用的保留调用的寄存器。

我认为优化器不能复制一条asm volatile语句,因此它将迫使编译器跳转到一个通用的结尾,而不是像在某些早期情况下那样复制结尾。

但是我不确定在自动柜员机挥发最终能存多少钱是有上限的

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用clang生成LLVM IR

来自分类Dev

使用LLVM C API生成对内在函数的调用

来自分类Dev

强制函数在Clang / LLVM中内联

来自分类Dev

如何为使用Clang LLVM编译的C ++代码生成图形代码配置文件报告?

来自分类Dev

如何使用QFontMetrics boundingRect测量多消息的大小?

来自分类Dev

LLVM(Clang)是否曾经使用GCC?

来自分类Dev

如何测量递归函数的时间和RAM使用率?

来自分类Dev

减少ARM的clang生成代码大小

来自分类Dev

llvm使用llvm指令获取被调用的函数名

来自分类Dev

如何使用llvm内部函数@ llvm.read_register?

来自分类Dev

llvm使用llvm指令获取被调用的函数名

来自分类Dev

使用clang从C代码生成SIMD代码

来自分类Dev

llvm使用库函数进行优化

来自分类Dev

使用LLVM传递添加内在函数

来自分类Dev

使用数组时的Julia LLVM函数签名

来自分类Dev

使用数组时的Julia LLVM函数签名

来自分类Dev

使用Clang构建V8并发出LLVM IR

来自分类Dev

将OpenMP与llvm-clang一起使用

来自分类Dev

使用cmake构建和包装LLVM clang 3.4

来自分类Dev

为什么FreeBSD不赞成使用GCC而赞成Clang / LLVM?

来自分类Dev

为什么在Visual Studio中使用LLVM + Clang时未定义__clang__?

来自分类Dev

clang vs gcc运行时差异:c ++类模板,使用clang生成,没有复制构造函数崩溃,g wcc,使用副本构造函数崩溃

来自分类Dev

如何从使用GetTextExtentPoint32()测量的文本大小中删除此边距?

来自分类Dev

使用 dplyr 应用自定义函数进行许多独特的测量

来自分类Dev

如何使用未知数量的参数处理用户函数以进行性能测量?

来自分类Dev

使用函数生成href

来自分类Dev

带有已删除“常规”大小写的专用模板函数无法使用g ++ <= 4.8.0和clang ++进行编译

来自分类Dev

Clang,LLVM和g ++

来自分类Dev

Clang,LLVM和g ++

Related 相关文章

  1. 1

    使用clang生成LLVM IR

  2. 2

    使用LLVM C API生成对内在函数的调用

  3. 3

    强制函数在Clang / LLVM中内联

  4. 4

    如何为使用Clang LLVM编译的C ++代码生成图形代码配置文件报告?

  5. 5

    如何使用QFontMetrics boundingRect测量多消息的大小?

  6. 6

    LLVM(Clang)是否曾经使用GCC?

  7. 7

    如何测量递归函数的时间和RAM使用率?

  8. 8

    减少ARM的clang生成代码大小

  9. 9

    llvm使用llvm指令获取被调用的函数名

  10. 10

    如何使用llvm内部函数@ llvm.read_register?

  11. 11

    llvm使用llvm指令获取被调用的函数名

  12. 12

    使用clang从C代码生成SIMD代码

  13. 13

    llvm使用库函数进行优化

  14. 14

    使用LLVM传递添加内在函数

  15. 15

    使用数组时的Julia LLVM函数签名

  16. 16

    使用数组时的Julia LLVM函数签名

  17. 17

    使用Clang构建V8并发出LLVM IR

  18. 18

    将OpenMP与llvm-clang一起使用

  19. 19

    使用cmake构建和包装LLVM clang 3.4

  20. 20

    为什么FreeBSD不赞成使用GCC而赞成Clang / LLVM?

  21. 21

    为什么在Visual Studio中使用LLVM + Clang时未定义__clang__?

  22. 22

    clang vs gcc运行时差异:c ++类模板,使用clang生成,没有复制构造函数崩溃,g wcc,使用副本构造函数崩溃

  23. 23

    如何从使用GetTextExtentPoint32()测量的文本大小中删除此边距?

  24. 24

    使用 dplyr 应用自定义函数进行许多独特的测量

  25. 25

    如何使用未知数量的参数处理用户函数以进行性能测量?

  26. 26

    使用函数生成href

  27. 27

    带有已删除“常规”大小写的专用模板函数无法使用g ++ <= 4.8.0和clang ++进行编译

  28. 28

    Clang,LLVM和g ++

  29. 29

    Clang,LLVM和g ++

热门标签

归档