我使用as
和gcc
按照this教程的建议,汇编和创建ARM汇编程序的可执行文件,如下所示:
给定汇编源文件program.s
,我运行:
as -o program.o program.s
然后:
gcc -o program program.o
但是,直接在程序集源上运行gcc
,如下所示:
gcc -o program program.s
产生相同的结果。
gcc
在幕后调用as
吗?是否有任何理由同时使用as
和gcc
只要gcc
能够从源生成可执行文件?
我在Raspberry Pi 3上运行它,Raspbian Jessie(Debian衍生物),gcc 4.9.2,为2.25。
答案 0 :(得分:4)
gcc在幕后调用各种各样的东西,不仅仅是为了ld,如果你想要证明它,这很容易进行检测(将CORRECT替换为ld和其他二进制文件与那些打印出他们的命令的二进制文件行,然后运行gcc并看到二进制文件被调用。)
当你使用gcc作为汇编程序时,它会通过一个C预处理程序,所以你可以做一些相当恶心的事情:
的start.s
//this is a comment
@this is a comment
#define FOO BAR
.globl _start
_start:
mov sp,#0x80000
bl hello
b .
.globl world
world:
bx lr
并且可以看到其他文件的更多信息
so.h
unsigned int world ( unsigned int, unsigned int );
#define FIVE 5
#define SIX 6
so.c
#include "so.h"
unsigned int hello ( void )
{
unsigned int a,b,c;
a=FIVE;
b=SIX;
c=world(a,b);
return(c+1);
}
构建
arm-none-eabi-gcc -save-temps -nostdlib -nostartfiles -ffreestanding -O2 start.s so.c -o so.elf
arm-none-eabi-objdump -D so.elf
制造
00008000 <_start>:
8000: e3a0d702 mov sp, #524288 ; 0x80000
8004: eb000001 bl 8010 <hello>
8008: eafffffe b 8008 <_start+0x8>
0000800c <world>:
800c: e12fff1e bx lr
00008010 <hello>:
8010: e92d4010 push {r4, lr}
8014: e3a01006 mov r1, #6
8018: e3a00005 mov r0, #5
801c: ebfffffa bl 800c <world>
8020: e8bd4010 pop {r4, lr}
8024: e2800001 add r0, r0, #1
8028: e12fff1e bx lr
这是一个非常简单的项目是so.i之后的预处理器,它获取包含文件并替换定义
# 1 "so.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "so.c"
# 1 "so.h" 1
unsigned int world ( unsigned int, unsigned int );
# 4 "so.c" 2
unsigned int hello ( void )
{
unsigned int a,b,c;
a=5;
b=6;
c=world(a,b);
return(c+1);
}
然后gcc调用实际的编译器(其程序名不是gcc)
产生so.s
.cpu arm7tdmi
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 1
.eabi_attribute 30, 2
.eabi_attribute 34, 0
.eabi_attribute 18, 4
.file "so.c"
.text
.align 2
.global hello
.syntax unified
.arm
.fpu softvfp
.type hello, %function
hello:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
push {r4, lr}
mov r1, #6
mov r0, #5
bl world
pop {r4, lr}
add r0, r0, #1
bx lr
.size hello, .-hello
.ident "GCC: (GNU) 6.3.0"
然后被送到汇编程序来生成so.o然后调用链接器将它们变成so.elf
现在你可以直接完成大部分的调用,这并不意味着这些程序有其他程序调用,gcc仍然会调用一个或多个程序来实际编译。
arm-none-eabi-as start.s -o start.o
arm-none-eabi-gcc -O2 -S so.c
arm-none-eabi-as so.s -o so.o
arm-none-eabi-ld start.o so.o -o so.elf
arm-none-eabi-objdump -D so.elf
给出相同的结果
00008000 <_start>:
8000: e3a0d702 mov sp, #524288 ; 0x80000
8004: eb000001 bl 8010 <hello>
8008: eafffffe b 8008 <_start+0x8>
0000800c <world>:
800c: e12fff1e bx lr
00008010 <hello>:
8010: e92d4010 push {r4, lr}
8014: e3a01006 mov r1, #6
8018: e3a00005 mov r0, #5
801c: ebfffffa bl 800c <world>
8020: e8bd4010 pop {r4, lr}
8024: e2800001 add r0, r0, #1
8028: e12fff1e bx lr
使用-S和gcc确实感觉有点不对,使用它就像感觉一样 更自然
arm-none-eabi-gcc -O2 -c so.c -o so.o
现在有一个我们没有提供的链接器脚本,工具链有默认值,我们可以控制它,具体取决于它的目标。
我不高兴看到新版本/当前版本的C评论是否容忍等等......过去不是这样的,必须是最新版本的新东西。
因此术语“工具链”是链接在一起的一些工具,一个按顺序链接到下一个工具。
并非所有编译器都采用汇编语言步骤。有些编译到中间代码然后有另一个工具将编译器特定的中间代码转换为汇编语言然后调用一些汇编程序(gcc的中间代码在编译步骤中的表内,其中clang / llvm你可以要求它编译成这段代码然后从那里转到其中一个目标的汇编语言)。有些编译器直接使用机器代码,而不是停留在汇编语言中。这可能就是其中一个人因为它在那里而爬山而已。就像用汇编语言编写操作系统一样。对于任何体面的大小项目和可以支持它的工具,您将拥有一个链接器,而汇编器是您为支持新目标而制作的第一个工具。处理器(芯片或IP或两者)供应商将拥有一个汇编程序,然后还有其他工具。尝试使用汇编语言手动编译上述简单的C程序,然后再使用汇编语言BY HAND再次尝试使用机器代码。您会发现使用汇编语言作为中间步骤对编译器开发人员来说更加理智,除了永远这样做之外,这也是继续这样做的一个很好的理由。
如果你在你正在使用的gnu工具链目录中闲逛,你可能会找到像cc1这样的程序
./libexec/gcc/arm-none-eabi/6.3.0/cc1 --help
The following options are specific to just the language Ada:
None found. Use --help=Ada to show *all* the options supported by the Ada front-end.
The following options are specific to just the language AdaSCIL:
None found. Use --help=AdaSCIL to show *all* the options supported by the AdaSCIL front-end.
The following options are specific to just the language AdaWhy:
None found. Use --help=AdaWhy to show *all* the options supported by the AdaWhy front-end.
The following options are specific to just the language C:
None found. Use --help=C to show *all* the options supported by the C front-end.
The following options are specific to just the language C++:
-Wplacement-new
-Wplacement-new= 0xffffffff
The following options are specific to just the language Fortran:
现在,如果您针对使用-save-temps保存的so.i文件运行该cc1程序,则会得到汇编语言文件。
您可能会继续深入了解目录或gnu工具来源以找到更多好东西......
请注意,此问题已经多次在stackoverflow中以各种方式提出。
另请注意,main()并不是我所演示的任何特殊内容。它可能是一些编译器,但我可以制作不需要该函数名的程序。