使用GCC逐步编译C?

使用GCC逐步编译C?,c,gcc,linker,C,Gcc,Linker,我正在尝试使用GCC将C源代码转换为可执行文件所需的四个步骤。前三步按预期进行,但最后一步给我带来了问题。我有两个文件:writeByte.h和writeByte.c,其中包含以下内容: // writeByte.h // USED GCC COMMANDS BY ORDER: // 1 - "gcc writeByte.c -o pre-processed.i -E" // 2 - "gcc pre-processed.i -o assembled.s -S" // 3 - "gcc asse

我正在尝试使用GCC将C源代码转换为可执行文件所需的四个步骤。前三步按预期进行,但最后一步给我带来了问题。我有两个文件:
writeByte.h
writeByte.c
,其中包含以下内容:

// writeByte.h
// USED GCC COMMANDS BY ORDER:
// 1 - "gcc writeByte.c -o pre-processed.i -E"
// 2 - "gcc pre-processed.i -o assembled.s -S"
// 3 - "gcc assembled.s -o compiled.o -c"
// 4 - ???

void writeByte(char* addr, char val);


据推测,要链接一个文件,我必须执行gcc compiled.o-o executable,但它说在
.text+0x20
,对
main
的引用是未定义的,所以我不知道如何遵循;DR:定义一个
main()
函数,你的程序就会运行。

来自C规范

5.1.2执行环境 定义了两个执行环境:独立的和托管的。 [……]

5.1.2.1独立式环境 在独立的环境中(在这种环境中,C程序的执行可能没有操作系统的任何好处),在程序启动时调用的函数的名称和类型是实现定义的。 [……]

5.1.2.2托管环境 [……]

5.1.2.2.1程序启动 程序启动时调用的函数名为
main
。[……]

此外:

J2未定义的行为 在以下情况下,该行为未定义:

  • [……]
  • 宿主环境中的程序不使用指定的形式(5.1.2.2.1)之一定义名为
    main
    的函数
托管环境 这很可能是您的情况。 这适用于典型的操作系统,如Linux、Unix、Mac OS X、Windows、Amiga OS等。在这种情况下,您的环境通常是托管环境

如果您在运行C编译器和链接器时没有选择或影响环境的任何选项,并且目标是这样一个典型的操作系统,并且您最终进行了链接,那么C编译器和链接器所做的假设将是托管环境。如上所述,这意味着您需要提供一个
main()
函数,以便宿主环境知道从何处启动C程序。因为您没有提供
main
函数,所以应用了子句J2未定义行为,链接器拒绝完成其工作

注意:在幕后,这些操作系统实际上提供了自己的自定义界面,请参见下文

解决方案:提供
main()
函数。

独立环境 独立环境通常发生在自己开发固件或操作系统时。在这种情况下,入口点由CPU定义。大多数CPU要么在预定义地址开始执行,要么在从预定义地址指定的向量表读取的可配置地址开始执行

自定义环境 除此之外,还有自定义环境。两种最常见的自定义环境是:

典型的操作系统 为了能够完成C规范规定之外的工作,操作系统定义了自己的环境。此环境通常是托管环境的扩展,将使用链接器指定的入口点。通常,该入口点实际上是另一个函数,通常称为
\u start
,由默认库(如libglibc)提供。此函数
\u start
由操作系统调用,该函数
\u start
然后实际调用
main

因此,与其提供
main
,不如提供
\u start
,或同等产品。 您可以编写自己的
\u start
函数或入口点。 然而,这样做的风险是,您的程序不必要地缺乏可移植性,并且您必须处理托管环境对您隐藏的操作系统问题。 因此,“普通”开发人员不建议将其用于“普通”程序

DLL环境 当程序应该作为其他程序的插件运行时,这些其他程序定义了一个自定义环境。 通常,该自定义环境实现为DLL(动态链接库)

嵌入式环境
对于一些嵌入式系统,工具链(编译器等)附带了库,这些库为该系统提供了自定义环境。这些环境具有介于独立环境和宿主环境之间的功能,入口点取决于相应的工具链。为了避免由于意外的入口点名称而引起的混淆,工具链通常使用
main
start
\u start
start
\u start
作为入口点的名称。

在C中,执行从
main
开始。你的程序必须有一个可以调用writeByte的主函数。@Jens Oh。。。我不知道我是怎么忘记的。可执行文件不是从
main
开始的。通常它们从
\u start
符号开始,它最终调用
main
@employeedrussian,这是正确的,但是,这是特定于操作系统的,没有在C中定义。我更新了答案以澄清这一点,感谢您的输入。
// writeByte.c
#include "writeByte.h"
void writeByte(char* addr, char val) { *addr = val; }