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

时间:2018-01-29 21:14:31

标签: c windows assembly executable filesize

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

this问题之后我能够创建等效的但是用汇编语言编写,这个程序的大小是39.6Kb。

这让我感到非常惊讶,因为我期望汇编程序比C程序小。正如问题所示,它使用了C头和gcc编译器。这是否会使装配程序更大,或者它们的大小大致相同是正常的吗?

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

test.c的:

3 个答案:

答案 0 :(得分:5)

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

现在你的文件大小表明你一直在看错了。您在调用二进制文件时正在查看的文件中包含大量其他内容。你想在这个上下文中比较苹果和苹果,然后比较函数的大小,机器代码,而不是容纳函数的容器的大小加上调试信息加上字符串加上许多其他东西。

您的实验存在缺陷,但结果非常松散地表明预期结果。但是,如果您以相同的方式生成代码。这种可能性很小,所以除非你以同样的方式生成代码,否则你不应该期待类似的结果。

采取这个简单的功能

var htmlString = '<img src="javascript:alert('XSS!')" />';
.
.
.
render() {
    return (
        <div>{htmlString}</div>
    );
}

同一个编译器产生了这个:

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

因为设置不同。 13指令vs 3,超过4倍。

人类可能直接从C生成这个,没有什么花哨的

00000000 <fun>:
   0:   e2811001    add r1, r1, #1
   4:   e0810000    add r0, r1, r0
   8:   e12fff1e    bx  lr
如果技术上必须在将该总和添加到a之前将其添加到b,则

不确定操作顺序。或者如果它无关紧要。我从左到右,编译器从右到左。

所以你可以说编译器和我的程序集产生了相同数量的二进制字节,或者你可以说编译器产生了超过4倍的东西。

采取上述做法,将其扩展为一个有用的实际程序。

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

修改

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

另请注意,编译器是由人类制作的,因此它们产生的输出与至少人类可以产生的效果相当,其他人类可以做得更好,许多人会根据您对更好和更差的定义做得更差。

答案 1 :(得分:3)

我同意old_time,但我也对基本事实进行了快速测试。使用VS-2017 Pro,我得到了类似于可执行文件大小的结果(~37KB),但前提是我查看了调试输出文件夹。在建立发布后,它接近~9KB。大部分差异在于调用OS / C运行时DLL所需的静态库的大小。

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

琐碎&#34;你好世界&#34;类程序不是C vs汇编程序的良好比较。没有足够的机会让编译器或人类在优化方面做很多事情。编写数学或数据处理库和应用程序并进行比较。我愿意打赌编译器会踢你的但是。

答案 2 :(得分:3)

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

#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字节。

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

您使用的静态链接c运行时给出的其余35kb +大小。即使你在asm上编写程序 - 你需要使用一些lib链接到printf。和你的lib包含一些与你的代码静态链接的代码。在这段代码中这35kb。

任务不是c ++ vs asm - 这里没有什么不同。使用中的任务c-runtime或不使用