一个经典程序的编译比较(gcc 编译器与自己的Cherry-C编译器)

iDogDogDog 2013-05-07 05:15:56
有这样一个看似平常的程序

#include <stdio.h>
void main()
{
long long d0 = 11;
long long d1 = 12;
long long d2 = 15;
long long d3 = 16;
long long d = (d0*d1)*(d2*d3);
printf("%lld\n",d3);
scanf("%s"," ");
}


但是在编译器眼里(在32位的环境下)这是一个经典的寄存器分配问题,研究这个程序的编译,发现一个整数表达式的编译最多同时需要6个寄存器,加上ESP(栈寄存器),EBP(帧寄存器),这也是为什么CPU需要8个通用寄存器的原因。

对于gcc,得到以下结果:

.file "test.c"
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "%lld\12\0"
LC1:
.ascii " \0"
LC2:
.ascii "%s\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
pushl %edi
pushl %esi
pushl %ebx
subl $84, %esp
call ___main
movl $11, 72(%esp)
movl $0, 76(%esp)
movl $12, 64(%esp)
movl $0, 68(%esp)
movl $15, 56(%esp)
movl $0, 60(%esp)
movl $16, 48(%esp)
movl $0, 52(%esp)
movl 76(%esp), %eax
movl %eax, %esi
imull 64(%esp), %esi
movl 68(%esp), %eax
imull 72(%esp), %eax
addl %eax, %esi
movl 64(%esp), %eax
movl %eax, 28(%esp)
movl 28(%esp), %eax
mull 72(%esp)
movl %eax, %ecx
movl %edx, %ebx
addl %ebx, %esi
movl %esi, %ebx
movl 60(%esp), %eax
movl %eax, %esi
imull 48(%esp), %esi
movl 52(%esp), %eax
imull 56(%esp), %eax
addl %eax, %esi
movl 48(%esp), %eax
mull 56(%esp)
addl %edx, %esi
movl %esi, %edx
movl %ebx, %esi
imull %eax, %esi
movl %edx, %edi
imull %ecx, %edi
addl %edi, %esi
mull %ecx
addl %edx, %esi
movl %esi, %edx
movl %eax, 40(%esp)
movl %edx, 44(%esp)
movl %eax, 40(%esp)
movl %edx, 44(%esp)
movl 48(%esp), %eax
movl 52(%esp), %edx
movl %eax, 4(%esp)
movl %edx, 8(%esp)
movl $LC0, (%esp)
call _printf
movl $LC1, 4(%esp)
movl $LC2, (%esp)
call _scanf
addl $84, %esp
popl %ebx
popl %esi
popl %edi
movl %ebp, %esp
popl %ebp
ret


Cherry-C编译器得到以下结果

.file "file.c"
.data
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $64, %esp
movl $0, 60(%esp)
movl $11, 56(%esp)
movl $0, 52(%esp)
movl $12, 48(%esp)
movl $0, 44(%esp)
movl $15, 40(%esp)
movl $0, 36(%esp)
movl $16, 32(%esp)
movl 60(%esp), %eax
movl %eax, %ecx
imull 48(%esp), %ecx
movl 52(%esp), %eax
imull 56(%esp), %eax
addl %eax, %ecx
movl 48(%esp), %eax
mull 56(%esp)
addl %edx, %ecx
movl %ecx, %edx
movl %eax, %ecx
movl %edx, %ebx
movl 44(%esp), %eax
movl %eax, %edi
imull 32(%esp), %edi
movl 36(%esp), %eax
imull 40(%esp), %eax
addl %eax, %edi
movl 32(%esp), %eax
mull 40(%esp)
addl %edx, %edi
movl %edi, %edx
movl %ebx, %edi
imull %eax, %edi
movl %edx, %esi
imull %ecx, %esi
addl %esi, %edi
mull %ecx
addl %edx, %edi
movl %edi, %edx
movl %edx, 28(%esp)
movl %eax, 24(%esp)
movl 24(%esp), %eax
movl %eax, 4(%esp)
movl 28(%esp), %edx
movl %edx, 8(%esp)
movl $LC0, (%esp)
call _printf
movl $LC1, 4(%esp)
movl $LC2, (%esp)
call _scanf
leave
ret
.section .rdata,"dr"
LC0:
.ascii "%lld\n\0"
LC1:
.ascii " \0"
LC2:
.ascii "%s\0"




是的,谁也没想到,在32位的环境下,64位的乘法会变的这样的复杂,而更为糟糕的是64位的除法更为的复杂,不得不编写一系列复杂的函数来实现(要是用汇编表达出来基本就是一部小说)。但是不管怎么样。可以从编译结果看出gcc编译器是一种倒推理的编译逻辑(从顶向下分析程序,这也是为什么gcc编译出的程序看上去有些古怪的原因),而Cherry-C是一种正推理的编译逻辑(从低向上分析程序),也许这两种方式各有优劣。
通过一个程序的行为结果分析它的实现,我把它就做《软件行为分析学》
...全文
142 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
疯狂的红豆 2013-05-07
  • 打赏
  • 举报
回复
先膜拜一下。。。
AnYidan 2013-05-07
  • 打赏
  • 举报
回复
Athenacle_ 2013-05-07
  • 打赏
  • 举报
回复
内个,我怎么觉得精华区几年前有一样的帖子啊
hugett 2013-05-07
  • 打赏
  • 举报
回复
bluewanderer 2013-05-07
  • 打赏
  • 举报
回复
Accumulator, Base, Counter, Data <- 最初的四个寄存器 Source Index, Destination Index, Base Pointer, Stack Point <- 8086 加的四个寄存器 8086 8个寄存器其实是这么来的。以前运算必须用A,实际需要的寄存器也会比现在更多。
  • 打赏
  • 举报
回复
图灵狗 2013-05-07
  • 打赏
  • 举报
回复
Dobzhansky 2013-05-07
  • 打赏
  • 举报
回复
学习了

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧