如何在Linux上从C源代码生成可编译的NASM汇编代码?

26

测试平台为32位Linux。

基本上,我知道gcc可以用来生成Intel和At&T风格的汇编代码,但似乎你不能直接使用nasm/tasm来编译gcc生成的Intel风格的汇编代码。

我正在进行一个项目分析,需要在Windows和Linux平台上分析汇编代码,所以我想知道它们是否都可以通过像nasm\yasm这样的平台无关汇编器来编译,这样我就可以更轻松地工作了...

所以我的问题是如何从c源代码在Linux上生成可编译的nasm汇编代码?


顺便提一下,gcc / gas 的 .intel_syntax / -masm=intel 语法类似于 MASM,而不是 NASM。请参见 https://stackoverflow.com/tags/intel-syntax/info。 - Peter Cordes
3个回答

42

我认为将目标文件进行反汇编比使用由gcc生成的汇编代码更好。

  1. 首先,从您的源代码生成一个目标文件:

    gcc -fno-asynchronous-unwind-tables -O2 -s -c -o main.o main.c
    

    -fno-asynchronous-unwind-tables:不生成不必要的段,如.eh_frame

    -O2:优化汇编代码以避免可怕的性能。可以选择使用-Os(减小体积而牺牲速度)或-O3(包括自动向量化在内的完全优化)。还可以通过-march=native-march=haswell-march=znver1(Zen)来为 CPU 进行调整并使用它支持的扩展。

    -s:生成较小的可执行文件(strip)

    -c -o main.o:编译但不链接,生成名为main.o的目标文件

  2. 使用objconv生成nasm代码:

  3. objconv -fnasm main.o
    

    结果将被存储在main.asm中。

  4. 结果将非常接近Nasm语法。然而,您可能需要进行一些微小的调整以消除警告/错误。只需尝试使用Nasm编译它即可。

  5. nasm -f elf32 main.asm
    

    通过手动修复错误/警告来解决问题。例如:

    • .SECTION行中删除align=Nexecute/noexecute单词。
    • global声明中删除文本: function
    • 删除default rel
    • 如有需要,删除空节等
  6. 使用gcc链接步骤3中由Nasm生成的main.o文件:

    gcc main.o
    

    你也可以使用ld来链接它,但这更困难。


2
你应该至少使用 gcc -O2 进行优化,除非你特别想要一个效率低下、臃肿的可执行文件和你不想看到的汇编代码。 - Peter Cordes
-fno-pie / -no-pie 是一个对于32位代码来说简化对全局变量和其他静态存储的访问非常不错的主意,除非您真的想将结果链接回到32位PIE。对于64位代码,使用nasm -felf64,RIP相对寻址是廉价且高效的。(所以保留default rel行)。 - Peter Cordes

10

默认情况下,您应该至少启用 gcc -O2。为什么有人会想要未经优化的代码,特别是如果您没有转换调试信息? - Peter Cordes
5
使用这个工具编译的大部分代码都是为了纯粹的教学目的。如果编译器进行了优化,它可能会采取“捷径”,这可能会让学生感到困惑,对吧?在这种情况下,更冗长地写代码并不是一件坏事。 - diogovk
在我看来,使用-O2编译选项编译int add(int a, int b) { return a+b; }函数的输出结果更有意义(即手动计算得到的结果),而不是使用-O0(https://godbolt.org/g/6cAehf)。请参考https://dev59.com/n1kT5IYBdhLWcg3wefUn(特别是Matt Godbolt的演讲链接)。关键是编写接受参数并返回值的函数,而不是一个被优化为打印和/或返回常量的main()函数。 - Peter Cordes
在每条C语句之间都将所有内容存储 / 重新加载到内存中(以支持调试器修改或跳转)会使其难以跟踪,除非您使用 -fverbose-asm 查看编译器汇编输出以让其为您跟踪C变量。 - Peter Cordes
无论如何,你说的“-O2”可能太多了。对于初学者来说,“-O1”或“-Og”可能是更好的选择。但是Stack Overflow会收到像“为什么编译器使用额外的堆栈空间”或浪费指令询问“-O0”输出的问题。 - Peter Cordes

1
这是一种不需要使用 objconv 的方法。
ndisasm -u <(objdump -j .text -d main.o | cut -d: -f2 | cut -d$'\t' -f 2 | perl -ne 'next if /file/; s/\s+//g; print' | xxd -r -p)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接