You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

gcc编译链接异常:main入口失效与文件找不到问题排查

问题描述

以下是极简测试代码:

#include <stdio.h>

void myFunc()
{
    puts("Greetings, Code 'Mon ...");
}

int main(int argc, char *argv[])
{
    puts("zMain 01.\n");
    myFunc();
    puts("zMain 02.\n");
}

通过Makefile生成的main_test2.run在Ubuntu 20.04.6 LTS环境下出现异常:

ld: warning: cannot find entry symbol _start; defaulting to 0000000000401030
...
/main_test/yikes01$ ./main_test2.run
bash: ./main_test2.run: No such file or directory

而在MinGW/Windows 10环境下,main_test2.run虽能运行,但未将main()作为程序入口点:

c:\tmp\main_test\yikes01>main_test2.run
Greetings, Code 'Mon ...

c:\tmp\main_test\yikes01>main_test.run
zMain 01.

Greetings, Code 'Mon ...
zMain 02.

Makefile内容如下:

cc=gcc -v
opts = 
link = ld

ifdef OS
    libs = -LC:/Windows/System32 -lkernel32 -lmingw32 -lcrtdll 
else
    libs = -lc
endif

all: main_test2.run main_test.run Makefile

# First function becomes void main(void) ...
main_test2.run: main_test.c
    $(cc) $(opts) -c main_test.c
    $(link)  main_test.o -o main_test2.run $(libs)
    rm -f main_test.o
    
main_test.run: main_test.c
    gcc main_test.c -o main_test.run

clean:
    rm -f *.o
    rm -f *.run

请问问题出在哪里?如何正确链接gmon_start?
注:调整参数会产生细微差异,但直接通过命令行编译的main_test.run始终正常。


问题原因与解决方案

核心问题:手动调用ld链接时缺失C运行时启动代码

直接用ld链接目标文件,没有引入C运行时(CRT)的启动代码,这会引发两个关键问题:

  1. 找不到程序入口_start:C程序的真正执行入口不是main,而是CRT提供的_start(Linux)或_mainCRTStartup(Windows/MinGW)。这段启动代码负责初始化运行环境、调用main函数,以及在main返回后完成资源清理。你手动用ld链接时,仅关联了自定义目标文件和libc,但未包含CRT启动对象,导致ld无法找到_start符号。
  2. MinGW下错误执行myFunc:当ld找不到合法入口时,会默认将目标文件中第一个出现的函数作为入口点。你的代码里myFunc定义在main之前,因此被错误当作入口执行。

另外Ubuntu下提示的" No such file or directory"并非文件不存在,而是动态链接器无法找到依赖库。手动用ld链接时未正确指定动态链接器路径(如/lib64/ld-linux-x86-64.so.2),导致系统无法加载必要的动态库。

正确的链接方式

推荐用gcc驱动链接——gcc会自动处理CRT启动代码、动态链接器路径、依赖库顺序等问题,避免手动调用ld的诸多适配问题。

方案1:修改Makefile用gcc完成链接

调整main_test2.run的规则,替换ld为gcc:

main_test2.run: main_test.c
    $(cc) $(opts) -c main_test.c
    gcc main_test.o -o main_test2.run
    rm -f main_test.o

此方式会自动包含所有必要的启动代码和库依赖,行为与main_test.run完全一致。

方案2:手动用ld时补充启动代码(仅作了解,不推荐)

若一定要使用ld,需明确引入CRT启动对象:

  • Linux/Ubuntu:需链接crt1.o、crti.o、crtn.o等启动文件,并指定动态链接器:
    ld /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o main_test.o /usr/lib/x86_64-linux-gnu/crtn.o -lc -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o main_test2.run
    
  • MinGW/Windows:需链接crt0.o和MinGW启动库:
    ld C:/MinGW/lib/crt0.o main_test.o -lmingw32 -lkernel32 -lcrtdll -o main_test2.run
    

该方式需适配不同平台的文件路径,维护成本高,不适合日常开发。

关于gmon_start的正确链接

gmon_start是性能分析工具gprof的依赖符号,只需在编译时添加-pg参数,gcc会自动处理相关链接逻辑:

cc=gcc -v -pg
opts = 
# 链接时仍用gcc,自动包含gprof所需代码
main_test2.run: main_test.c
    $(cc) $(opts) -c main_test.c
    gcc $(opts) main_test.o -o main_test2.run
    rm -f main_test.o

内容的提问来源于stack exchange,提问作者Randall Nagy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 00:42:43