【问题标题】:How to change entry point of C program with gcc?如何使用 gcc 更改 C 程序的入口点?
【发布时间】:2021-05-08 14:56:08
【问题描述】:

如何更改使用 gcc 编译的 C 程序的入口点?
就像在下面的代码中

#include<stdio.h>
int entry()  //entry is the entry point instead of main
 {
   return 0;
 }

【问题讨论】:

  • @iandotkelly 不是 OP,但我需要使用检查点库,这需要我将 main() 更改为其他内容;)
  • @Nubcake 你知道链接器的选项--wrap=xxx吗?它将xxx 的所有引用替换为__wrap_xxx,并将xxx 的所有定义替换为__real_xxx。我成功地用它来测试main()

标签: c main entry-point


【解决方案1】:

这是一个链接器设置:

-Wl,-eentry

-Wl,... 事物将参数传递给链接器,链接器采用 -e 参数来设置入口函数

【讨论】:

  • 这是我在使用此选项编译 hello world C 程序时得到的:$ gcc -Wl,-emymain t27.c /usr/lib/gcc/i686-redhat-linux/4.8.2/../../../crt1.o: In function '_start': (.text+0x18): undefined reference to 'main'
  • @LeeDuhem,这是因为您将程序与标准 c 运行时库链接。与 c 运行时库链接的程序中的入口点是 _start。 Start 引用了您的程序的 main()(它希望您的程序具有 main() func 而不是您的自定义 func)。尽量不要链接到 crt 并将入口点指定为 your_main 看看会发生什么。
  • @LeeDuhem, -nostdlibs 那个标志是。
  • -nostartfiles 是您想要的实际标志,它省略了包含 _start 的 crt*.o 文件,但仍然允许您使用 libc(除非您还使用 -nostdlib 或 -nodefaultlibs,其中如果您仍然可以使用 -lc -lgcc 等手动指定它们...)
  • 我相信有一个错字:应该是-Wl,--entry="MyCutomEntryFunction"-Wl,-e="MyCutomEntryFunction"
【解决方案2】:

您可以将源代码修改为:

#include<stdio.h>

const char my_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";

int entry()  //entry is the entry point instead of main
{
   exit(0);
}

“.interp”部分将使您的程序能够调用外部共享库。 exit 调用将使您的入口函数退出程序而不是返回。

然后将程序构建为可执行的共享库:

$ gcc -shared -fPIC -e entry test_main.c -o test_main.so
$ ./test_main

【讨论】:

  • entry 函数的调用约定是什么? C-runtime是这样初始化的吗?
  • 您能否解释一下这是什么意思“将程序构建为一个可执行共享库两者兼而有之?
  • @harper:这不是 C 兼容的调用约定。 ELF 入口点 ABI 的主要参数在堆栈指针中,指向由 argc、argv 指针、null、env 指针、null、aux 向量表组成的“数组”。一些拱门在特定寄存器中有额外的参数。
  • 不起作用..我得到:无法执行二进制文件:执行格式错误
【解决方案3】:

如果您使用的是提供GNU Binutils 的系统(如 Linux), 你可以使用objcopy 命令 使任意函数成为新的入口点。

假设一个名为program.c 的文件包含entry 函数:

$ cat > program.c
#include <stdio.h>
int entry()
{
    return 0;
}
^D
  1. 您首先使用-c 编译它以生成可重定位的目标文件:

    $ gcc -c program.c -o program.o
    
  2. 然后你将entry重新定义为main

    $ objcopy --redefine-sym entry=main program.o
    
  3. 现在使用 gcc 编译新的目标文件:

    $ gcc program.o -o program
    

注意:如果您的程序已经有一个名为 main 的函数,则在第 2 步之前,您可以执行单独的 objcopy 调用:

objcopy --redefine-sym oldmain=main program.o

【讨论】:

    【解决方案4】:

    最小的可运行示例和其他答案的注释

    main.c

    #include <stdio.h>
    #include <stdlib.h>
    
    int mymain(void) {
        puts("hello");
        exit(0);
    }
    

    编译运行:

    gcc -nostartfiles -Wl,--entry=mymain -o main.out main.c
    # or -Wl,-emymain
    ./main.out 1 2 3
    

    注释:

    • 没有-nostartfiles,链接会失败并显示:

      /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
      (.text+0x20): undefined reference to `main'
      collect2: error: ld returned 1 exit status
      

      大概是因为runs before main_start中的glibc设置代码通常会调用main

    • 没有为您设置命令行参数,大概是因为它们将由在 main 之前运行的 glibc 代码设置,因此尝试使用它们会打印未定义的值。我还没有找到适合他们的方法。

    在 Ubuntu 20.10 中测试。

    【讨论】:

    • 不起作用,显然警告很严重。
    • @ScottFranco 顺便说一句,你的 GCC 版本/操作系统版本是什么?
    • C:\projects\petit_ami>gcc -v ... gcc 版本 9.2.0 (MinGW.org GCC Build-2)
    • @ScottFranco 警告是由小错字引起的 -eentry= 应该是 --entry= ;我已经相应地编辑了答案。
    • @Demi-Lune 不错的收获!我想知道在我的测试中它是如何处理错字的!
    猜你喜欢
    • 2019-03-18
    • 1970-01-01
    • 2015-02-25
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-02
    相关资源
    最近更新 更多