代码之家  ›  专栏  ›  技术社区  ›  Xantium

汇编程序的大小是否与C程序几乎相同

  •  4
  • Xantium  · 技术社区  · 7 年前

    例如:我创建了一个打印“Hello,World”的简单C程序,对其进行编译,并创建了一个大小为39.8Kb的可执行文件。

    下列的 this 问题我能够创建等效的程序集,但它是用汇编编写的,这个程序的大小是39.6Kb。

    这让我大吃一惊,因为我希望汇编程序比C程序小。如问题所示,它使用C头和gcc编译器。这会使汇编程序变得更大,还是两者的大小大致相同是正常的?


    使用 strip 命令I减少了两个文件。这删除了调试代码,现在两者的文件大小非常相似。均为18.5Kb。

    测验c:

    3 回复  |  直到 7 年前
        1
  •  6
  •   old_timer    7 年前

    如果您的手工编写的代码与编译后的函数相当,那么请确保它们的大小相似,它们正在做同样的事情,如果您可以与编译器竞争,那么您将是相同或相似的。

    现在,您的文件大小表明您看到的都是错误的东西。您正在查看的名为二进制文件的文件中有大量其他内容。在这个上下文中,您想比较各个苹果,然后比较函数的大小、机器代码,而不是保存函数的容器的大小加上调试信息加上字符串再加上其他一些东西。

    你的实验有缺陷,但结果很粗略地表明了预期的结果。但如果您以相同的方式生成代码,则会出现这种情况。这种可能性很小,所以说不,除非以相同的方式生成代码,否则不应该期望类似的结果。

    以这个简单的函数为例

    unsigned int fun ( unsigned int a, unsigned int b)
    {
        return(a+b+1);
    }
    

    同一编译器生成了以下内容:

    00000000 <fun>:
       0:   e52db004    push    {r11}       ; (str r11, [sp, #-4]!)
       4:   e28db000    add r11, sp, #0
       8:   e24dd00c    sub sp, sp, #12
       c:   e50b0008    str r0, [r11, #-8]
      10:   e50b100c    str r1, [r11, #-12]
      14:   e51b2008    ldr r2, [r11, #-8]
      18:   e51b300c    ldr r3, [r11, #-12]
      1c:   e0823003    add r3, r2, r3
      20:   e2833001    add r3, r3, #1
      24:   e1a00003    mov r0, r3
      28:   e28bd000    add sp, r11, #0
      2c:   e49db004    pop {r11}       ; (ldr r11, [sp], #4)
      30:   e12fff1e    bx  lr
    

    还有这个

    00000000 <fun>:
       0:   e2811001    add r1, r1, #1
       4:   e0810000    add r0, r1, r0
       8:   e12fff1e    bx  lr
    

    因为设置不同。13条指令比3条指令大4倍以上。

    一个人可能直接从C生成这个,没什么特别的

    add r0,r0,r1
    add r0,r0,#1
    bx lr
    

    从操作顺序来看,不确定在将金额添加到a之前,您是否必须将1添加到b。或者,如果这无关紧要。我从左到右,编译器从右到左。

    因此,您可以说编译器和我的程序集生成的二进制字节数相同,或者您可以说编译器生成的二进制字节数是我的4倍以上。

    将以上内容扩展到一个真正的程序中,可以做一些有用的事情。

    向读者进行练习(OP,请不要破坏它),找出为什么编译器可以生成两个大小如此不同的正确解决方案。

    编辑

    .exe、elf和其他提到的“二进制”格式可以包含调试信息,ascii字符串包含函数/标签的名称,这些名称构成了漂亮的调试屏幕。它们是“二进制”的一部分,因为它们是行李的一部分,但不是执行该程序时使用的机器代码或数据,至少不是我提到的东西。您可以在不更改程序所需的机器代码或数据的情况下,操纵程序的大小。exe或使用编译器设置的其他文件格式,因此相同的编译器汇编器链接器或汇编器链接器路径可以通过包含或不包含此附加行李,使二进制文件在该单词的某些意义上变大或变小。因此,这是理解文件大小的一部分,也是为什么即使您的hello world程序大小不同,但如果一个文件长10个字节,而另一个文件长10个字节,那么整个文件的大小可能大致相同。exe为40K,则噪声中有10个字节。但如果我理解你的问题,那么10个字节就是你感兴趣的,你想知道编译的C和手写的C之间的比较。

    还要注意的是,编译器是由人类制造的,因此它们产生的输出与这些人所能产生的结果相当,其他人可以做得更好,许多人做得更差,这取决于你对更好和更差的定义。

        2
  •  5
  •   RbMm    7 年前

    绝对大小为39+Kb,与编译器和使用的语言无关( c/c++ asm公司 )不同的优化、调试信息等可以改变这个微小代码的大小,比如1000字节。但不是更多。i用于测试构建下一个程序

    #include <Windows.h>
    #include <stdio.h>
    void ep(void*)
    {
        ExitProcess(printf("Hello, World"));
    }
    

    链接器选项:

    /INCREMENTAL:NO /NOLOGO /MANIFEST:NO /NODEFAULTLIB 
    /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /LTCG /ENTRY:"ep" /MACHINE:X64 kernel32.lib msvcrt.lib
    

    并为x86/x64获取大小为2560字节的exe。

    有什么不同?在里面 /NODEFAULTLIB 和我的版本 msvcrt.lib -这是纯导入库。

    由静态链接的c运行时提供的剩余35kb以上的大小。即使您在asm上编写程序,也需要使用一些lib来链接 printf . 以及包含一些与代码静态链接的代码的lib。在此代码中为35kb。

    任务不是c++与asm-这里没有什么不同。任务正在使用c-runtime或未使用

        3
  •  4
  •   jwdonahue    7 年前

    我同意old\u time,但我也做了一个快速测试,以了解地面真相。使用VS-2017 Pro,我在可执行文件的大小上得到了类似的结果(约37KB),但只有在查看debug output文件夹的情况下。在构建发布版之后,它的大小接近9KB。这种差异主要在于调用OS/C运行时DLL所需的静态库的大小。

    编辑:尽管大多数现代C编译器可以匹配或优于大多数手工编写的汇编代码,但手工编写的种类可以更小,因为它不需要所有的C运行时,但这种差异很少足以保证汇编代码的额外开发和维护成本,特别是对于非平凡的应用程序。有一个原因是,大多数现代操作系统内核主要是用C或其他高级语言编写的,只有少数关键函数中的针孔汇编优化。

    普通的“hello world”类程序对于C和汇编程序来说不是一个很好的比较。编译器或人类没有足够的机会在优化方面做很多工作。编写一个数学或数据处理库和应用程序,并进行比较。我敢打赌编译器会踢你的,但是。

    推荐文章