gcc可以编译python程序吗_gccc语⾔编译流程
1 前⾔
最近⾥讨论个C语⾔的⼩程序,看起来都不是很难,但是⼤家对答案有争论,所以想讨论编译原理,做嵌⼊式要对编译原理有⼀定的了解,所以转了这篇⽂章。
我们之前讨论的问题如下代码
#include
#include
#define WEIQIFA 0;
int main(void)
{
int i = WEIQIFA;
i = i++;
i++;
printf("%d\n",i);
return 0;
}
原来是没有那个宏WEIQIFA的,但是我为了举例编译原理,特意加上去,编译的第⼀步就是做宏替换
预编译后变成下⾯这样
int main(void)
{
int i = 0;;
i = i++;
i++;
printf("%d\n",i);
return 0;
}
⽤g++ -g -Wstrict-prototypes -Wall -Wunused -o test test001.c 编译
然后⽤objdump -j .text -Sl test | more 查看代码可以看到汇编代码如下
main():
/data/weiqifa/c/bianyiyuanli/test001.c:7
#include
#define WEIQIFA 0;
int main(void)
{
400526: 55 push %rbp
400527: 48 89 e5 mov %rsp,%rbp
40052a: 48 83 ec 10 sub $0x10,%rsp
/data/weiqifa/c/bianyiyuanli/test001.c:9
int i = WEIQIFA;
40052e: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
/data/weiqifa/c/bianyiyuanli/test001.c:11
i = i++;
400535: 8b 45 fc mov -0x4(%rbp),%eax
400538: 8d 50 01 lea 0x1(%rax),%edx
40053b: 89 55 fc mov %edx,-0x4(%rbp)
40053e: 89 45 fc mov %eax,-0x4(%rbp)
/data/weiqifa/c/bianyiyuanli/test001.c:12
i++;
400541: 83 45 fc 01 addl $0x1,-0x4(%rbp)
/data/weiqifa/c/bianyiyuanli/test001.c:14
printf("%d\n",i);
400545: 8b 45 fc mov -0x4(%rbp),%eax
400548: 89 c6 mov %eax,%esi
40054a: bf e4 05 40 00 mov $0x4005e4,%edi
40054f: b8 00 00 00 00 mov $0x0,%eax
400554: e8 a7 fe ff ff callq 400400
/
data/weiqifa/c/bianyiyuanli/test001.c:16
return 0;
400559: b8 00 00 00 00 mov $0x0,%eax
/data/weiqifa/c/bianyiyuanli/test001.c:17
}
当时⼤家讨论很激烈
2 正⽂
⼤家肯定都知道计算机程序设计语⾔通常分为机器语⾔、汇编语⾔和⾼级语⾔三类。⾼级语⾔需要通过翻译成机器语⾔才能执⾏,⽽翻译的⽅式分为两种,⼀种是编译型,另⼀种是解释型,因此我们基本上将⾼级语⾔分为两⼤类,⼀种是编译型语⾔,例如C,C++,Java,另⼀种是解释型语⾔,例如Python、Ruby、MATLAB 、JavaScript。
本⽂将介绍如何将⾼层的C/C++语⾔编写的程序转换成为处理器能够执⾏的⼆进制代码的过程,包括四个步骤:预处理(Preprocessing)
编译(Compilation)
汇编(Assembly)
链接(Linking)
1、GCC ⼯具链介绍
GCC(GNU Compiler Collection,GNU编译器套件),是由 GNU 开发的编程语⾔编译器。它是以GPL许可证所发⾏的⾃由软件,也是GNU计划的关键部分。GCC原本作为GNU操作系统的官⽅编译器,现已被⼤多数类Unix操作系统(如Linux、BSD、Mac OS X等)采纳为标准的编译器,GCC同样适⽤于微软的Windows。GCC是⾃由软件过程发展中的著名例⼦,由⾃由软件基⾦会以GPL协议发布。
C运⾏库
C语⾔标准主要由两部分组成:⼀部分描述C的语法,另⼀部分描述C标准库。C标准库定义了⼀组标准头⽂件,每个头⽂件中包含⼀些相关的函数、变量、类型声明和宏定义,譬如常见的printf函数便是⼀个C标准库函数,其原型定义在stdio头⽂件中。
C语⾔标准仅仅定义了C标准库函数原型,并没有提供实现。因此,C语⾔编译器通常需要⼀个C运⾏
时库(C Run Time Libray,CRT)的⽀持。C运⾏时库⼜常简称为C运⾏库。与C语⾔类似,C++也定义了⾃⼰的标准,同时提供相关⽀持库,称为C++运⾏时库。
2、举个例⼦
由于GCC⼯具链主要是在Linux环境中进⾏使⽤,因此本⽂也将以Linux系统作为⼯作环境。为了能够演⽰编译的整个过程,本节先准备⼀个C语⾔编写的简单Hello程序作为⽰例,其源代码如下所⽰:
#include
#include
#define WEIQIFA 0;
int main(void)
{
int i = WEIQIFA;
i = i++;
i++;
printf("%d\n",i);
return 0;
}
3、编译过程
3.1 预处理
预处理的过程主要包括以下过程:
1、将所有的#define删除,并且展开所有的宏定义,并且处理所有的条件预编译指令,⽐如#if #ifdef #elif #else #endif等。
2、处理#include预编译指令,将被包含的⽂件插⼊到该预编译指令的位置。
3、删除所有注释“//”和“/* */”。
4、添加⾏号和⽂件标识,以便编译时产⽣调试⽤的⾏号及编译错误警告⾏号。
5、保留所有的#pragma编译器指令,后续编译过程需要使⽤它们。
使⽤gcc进⾏预处理的命令如下:
$gcc -E test001.c -o test001.i // 将源⽂件test001.c⽂件预处理⽣成test001.i
// GCC的选项-E使GCC在进⾏完预处理后即停⽌
test001.i⽂件可以作为普通⽂本⽂件打开进⾏查看,其代码⽚段如下所⽰:
extern char *__stpncpy (char *__restrict __dest,
const char *__restrict __src, size_t __n)
__attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
extern char *stpncpy (char *__restrict __dest,
const char *__restrict __src, size_t __n)
__attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
# 658 "/usr/include/string.h" 3 4
# 3 "test001.c" 2
# 6 "test001.c"
int main(void)
{
int i = 0;;
i = i++;
i++;
printf("%d\n",i);
return 0;
}
3.2 编译
编译过程就是对预处理完的⽂件进⾏⼀系列的词法分析,语法分析,语义分析及优化后⽣成相应的汇编代码。使⽤gcc进⾏编译的命令如下:
$ gcc -S test001.i -o test001.s // 将预处理⽣成的test001.i⽂件编译⽣成汇编程序test001.s
// GCC的选项-S使GCC在执⾏完编译后停⽌,⽣成汇编程序
上述命令⽣成的汇编程序test001.s的代码⽚段如下所⽰,其全部为汇编代码。
weiqifa@ubuntu:~/c/bianyiyuanli$ cat test001.s
.file "test001.c"
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $0, -4(%rbp)
movl -4(%rbp), %eax
leal 1(%rax), %edx
movl %edx, -4(%rbp)
movl %eax, -4(%rbp)
addl $1, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
linux下gcc编译的四个步骤movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609"
.section .note.GNU-stack,"",@progbits
weiqifa@ubuntu:~/c/bianyiyuanli$
3.3 汇编
汇编过程调⽤对汇编代码进⾏处理,⽣成处理器能识别的指令,保存在后缀为.o的⽬标⽂件中。由于每⼀个汇编语句⼏乎都对应⼀条处理器指令,因此,汇编相对于编译过程⽐较简单,通过调⽤Binutils中的汇编器as根据汇编指令和处理器指令的对照表⼀⼀翻译即可。
当程序由多个源代码⽂件构成时,每个⽂件都要先完成汇编⼯作,⽣成.o⽬标⽂件后,才能进⼊下⼀步的链接⼯作。注意:⽬标⽂件已经是最终程序的某⼀部分了,但是在链接之前还不能执⾏。
使⽤gcc进⾏汇编的命令如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论