当前位置: 首页 > 科技观察

GNUC编译器程序员初学者指南

时间:2023-03-11 21:25:02 科技观察

C语言为新老程序员所熟知并广受好评。C语言编写的源文件代码使用标准的英文术语,便于人们阅读。但是,计算机只能理解二进制代码。要将代码转换为机器语言,您需要一个称为编译器的工具。最常见的编译器是GCC(GNUCompilerCollection)。编译过程涉及一系列中间步骤和相关工具。安装GCC要验证GCC是否已安装在您的系统上,请使用gcc命令:$gcc--version如有必要,请使用您的包管理器来安装GCC。在基于Fedora的系统上,使用dnf:$sudodnfinstallgcclibgcc在基于Debian的系统上,使用apt:$sudoaptinstallbuild-essential安装后,如果你想查看GCC安装位置,使用:$whereisgccdemonstrates使用GCC编译一个简单的C程序下面是一个简单的C程序,用于演示如何使用GCC进行编译。打开您最喜欢的文本编辑器并将此代码粘贴到其中://hellologcc.c#includeintmain(){printf("Hello,GCC!\n");return0;}将文件保存为hellologcc.c,然后编译:$lshellogcc.c$gcchellologcc.c$ls-1a.outhellogcc.c可以看到,a.out是编译后默认生成的二进制文件.要查看新编译的应用程序的输出,只需像运行任何本机二进制文件一样运行它:$./a.outHello,GCC!将输出文件filename命名为a.out比较莫名其妙,所以,如果要指定可执行文件的名称,可以使用-o选项:(LCTT译注:注意这与a.out无关Linux内核最近弃用的格式,但名字是一样的。这里生成的a.out是ELFFormat——我不知道是谁给它取了一个破名字a.out。在我看来,默认的输出文件name应该是去掉.c扩展名后的名字。通过wxy)$gcc-ohellologcchellologcc.c$lsa.outhellocchellologcc.c$./hellogcc你好,GCC!在开发需要编译多个C源文件的大型应用程序时,此选项很有用。GCC编译中的中间步骤编译实际上有四个步骤,尽管GCC会自动为简单的用例执行这些步骤。预处理:GNU的C预处理器(cpp)解析头文件(#include语句),扩展宏定义(#define语句),使用扩展后的源文件代码生成中间文件,如hellocc.i。编译:在此期间,编译器将经过预处理的源文件代码转换为指定CPU架构的汇编代码。生成的程序集文件以.s扩展名命名,例如本例中的hellocc.s。汇编:汇编程序(as)将汇编代码转换为目标机器代码并将其放入目标文件中,例如hellocc.o。链接:链接器(ld)链接目标代码和库代码以生成可执行文件,例如hellocc。运行GCC时,可以使用-v选项查看每一步的详细信息:$gcc-v-ohellologcchellologcc.c编译器流程图手动编译代码,体验编译的每一步可能会有用,所以在一些在这种情况下,您的GCC不需要完成所有步骤。首先,删除当前文件夹下生成的除源文件外的文件。$rma.outhellocc.o$lshellogcc.c预处理器首先,启动预处理器,将其输出重定向到hellocc.i:预处理器在头文件和扩展宏中包含源文件代码。编译器您现在可以将代码编译为汇编代码。使用-S选项将GCC设置为仅生成汇编代码:$gcc-Shellologcc.i$lshellogcc.chellologcc.ihellocc.s$cathellocc.s查看汇编代码以查看生成的内容。汇编使用你刚刚生成的汇编代码来创建一个目标文件:$as-ohellologcc.ohellologcc.s$lshellogcc.chellocc.ihellocc.ohellologcc.slinking要生成一个可执行文件,你必须把目标文件链接到它所依赖的库。这不像前面的步骤那么简单,但是很有启发性:$ld-ohellologcchellologcc.old:warning:cannotfindentrysymbol_start;默认为0000000000401000ld:hellocc.o:infunction`main`:hellocc.c:(.text+0xa):undefinedreferenceto`puts'链接器找到libc.so库后,出现对未定义puts的引用错误。您必须找出适当的链接器选项来链接必要的库以解决此问题。这不是一个小技巧,它取决于你系统的布局。在链接时,您必须将您的代码链接到核心运行时(CRT)目标,这是一组帮助二进制可执行文件启动的子例程。链接器还需要知道在哪里可以找到重要的系统库,包括libc和libgcc,尤其是其中的特殊开始和结束指令。这些指令可以通过--start-group和--end-group选项分隔,或者通过使用crtbegin.o和crtend.o的路径分隔。此示例使用RHEL8上的路径,因此您可能需要根据您的系统调整路径。$ld-dynamic-linker/lib64/ld-linux-x86-64.so.2\-ohello\/usr/lib64/crt1.o/usr/lib64/crti.o\--start-group\-L/usr/lib/gcc/x86_64-redhat-linux/8\-L/usr/lib64-L/lib64hello.o\-lgcc\--as-needed-lgcc_s\--no-as-needed-lc-lgcc\--end-group\/usr/lib64/crtn.o在Slackware上,相同的链接过程使用不同的路径集,但是,您可以在此处看到相似之处:$ld-static-ohello\-L/usr/lib64/gcc/x86_64-slackware-linux/11.2.0/\/usr/lib64/crt1.o/usr/lib64/crti.ohello.o/usr/lib64/crtn.o\--start-group\-lc-lgcc-lgcc_eh\--end-group现在,运行生成的可执行文件:$./helloHello,GCC!一些有用的实用程序这里有一些有助于检查文件类型的实用程序,用于链接到可执行文件的符号表和库的实用程序。使用文件实用程序确定文件类型:$filehellocc.chellogcc.c:Csource,ASCIItext$filehellocc.ohellogcc.o:ELF64-bitLSBrelocatable,x86-64,version1(SYSV),not剥离$文件helloccchellogcc:ELF64位LSB可执行文件,x86-64,版本1(SYSV),动态链接,解释器/lib64/ld-linux-x86-64.so.2,BuildID[sha1]=bb76b241d7d00871806e9fa5e814fee276d5bNd1a,适用于Linux3.2.0,未剥离使用目标文件的nm实用程序列出符号表:$nmhellocc.o0000000000000000TmainUputs使用ldd实用程序列出动态链接库:$lddhellocclinux-vdso.so.1(0x00007ffe3bdd7000)libc.so.6=>/lib64/libc.so.6(0x00007f223395e000)/lib64/ld-linux-x86-64.so.2(0x00007f2233b7e000)总结在本文中,您了解了GCC编译的各种中间步骤,以及用于检查的实用程序链接到可执行文件中的文件类型、符号表和库。下次使用GCC时,您将了解它为您生成二进制文件所经历的步骤,并且当出现问题时,您将知道如何逐步处理它。