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

如何重写__libc_start_main,使其不调用main而执行自定义函数?

完全可以实现!

当然没问题——重写__libc_start_main来替换最终调用的目标函数,正是解决你当前"main运行两次"问题的完美方案。

先给你理清楚核心逻辑:__libc_start_main是glibc中负责启动流程的关键函数,它会完成所有初始化工作(比如全局对象构造、环境变量初始化、线程设置等),最后才调用程序的main函数。我们的目标就是劫持这个函数,让它在完成初始化后调用我们的自定义函数,而非原main。

具体实现步骤(最稳妥的动态劫持方案)

推荐用LD_PRELOAD加载自定义共享库的方式,这种方法不需要修改原程序代码,兼容性也强:

  1. 编写自定义共享库代码
    我们需要实现自己的__libc_start_main,在里面替换掉原main函数指针,再调用真正的glibc版本完成初始化和启动:

    #include <stdio.h>
    #include <dlfcn.h>
    
    // 自定义的替代函数,签名要和main完全一致
    int my_custom_main(int argc, char** argv, char** envp) {
        printf("Running my custom main instead of original!\n");
        
        // 如果需要调用原main,可以在这里保存原指针后调用
        // return original_main(argc, argv, envp);
        
        return 0;
    }
    
    // 定义真正的__libc_start_main函数指针类型
    typedef int (*libc_start_main_t)(int (*)(int, char**, char**), int, char**, 
                                    void (*)(void), void (*)(void), void (*)(void), void*);
    libc_start_main_t real_libc_start_main;
    
    // 我们的__libc_start_main实现
    int __libc_start_main(int (*original_main)(int, char**, char**), int argc, char** ubp_av,
                          void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void* stack_end) {
        // 获取glibc真正的__libc_start_main函数
        real_libc_start_main = (libc_start_main_t)dlsym(RTLD_NEXT, "__libc_start_main");
        if (!real_libc_start_main) {
            fprintf(stderr, "Failed to get real __libc_start_main: %s\n", dlerror());
            return 1;
        }
    
        // 调用真正的启动函数,但把目标替换成我们的自定义函数
        return real_libc_start_main(my_custom_main, argc, ubp_av, init, fini, rtld_fini, stack_end);
    }
    
  2. 编译共享库
    用gcc编译成动态链接库:

    gcc -shared -fPIC -o libcustommain.so custom_main.c -ldl
    
  3. 运行目标程序
    通过LD_PRELOAD让程序优先加载我们的库:

    LD_PRELOAD=./libcustommain.so ./your_target_program
    

关键细节提醒

  • 签名一致性:自定义函数的签名必须和标准main完全匹配(包括第三个环境变量参数,有些系统会隐式传递,但显式声明更稳妥)。
  • 避免递归调用:用RTLD_NEXT获取原函数,确保我们的实现不会无限递归调用自己。
  • 原main的调用:如果需要保留原main的功能,可以在自定义函数中调用保存下来的original_main指针。
  • 架构兼容性:不同CPU架构的__libc_start_main签名可能有细微差异,比如参数顺序或类型,需要根据目标平台调整。

这种方案完全跳过了原main的自动调用,只会执行一次我们的自定义函数,完美解决你遇到的"main运行两次"问题。

内容的提问来源于stack exchange,提问作者Rahul Dugar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:19:47