【问题标题】:How to make other function as entry point other than main() in C如何在 C 中将其他函数作为除 main() 之外的入口点
【发布时间】:2012-03-13 01:52:05
【问题描述】:

每个程序都有一个main(),程序从那里开始执行。是否可以在没有main() 的情况下编写程序并将另一个函数作为入口点?如果是这样,谁能告诉我怎么做?我使用的是 Linux?

【问题讨论】:

  • 不将main 作为入口点,您想达到什么目的?
  • @eduffy 正在阅读一本关于 C 的书,其中提到 main() 和许多其他函数一样只是一个函数,所以有这个疑问,
  • 查看这篇文章 linuxgazette.net/issue84/hawk.html,看看在调用 main() 之前会发生什么。
  • 检查here。如果你想玩得开心,你也可以疯狂地编写自己的程序集。

标签: c linux


【解决方案1】:

如果您使用 gcc 进行编译,指定 -e <symbol> 选项将使您可以将入口点更改为函数 symbol()

【讨论】:

  • 这可能会严重破坏事情,因为它会绕过标准库假设已经运行的启动代码......
  • 当然,但这回答了“是否可以编写一个没有 main() 的函数并将其他函数作为入口点?如果可以,请告诉我怎么做。我我正在使用 linux”,而不是“如何将入口点更改为 C 程序并避免严重破坏”。
  • 很公平。这更像是对 OP 的评论而不是对您的回答的批评。
【解决方案2】:

您可以以可移植的方式执行此操作,只需将此头文件包含在您的主程序中:

int nomDePlume(int argc, char *argv[]);
int main(int argc, char *argv[]) { return nomDePlume(argc, argv); }

然后提供您自己的main 变体:

int nomDePlume(int argc, char *argv[]) {
    weaveYourMagic();
    return 42;
}

这实际上并没有改变可执行文件的入口点(这是非常特定于实现的东西),但它确实让你可以随意调用你的程序入口点(当然,在合法标识符的范围内)。


如果您根本不想要main(即使在头文件中),它会变得有点棘手。

那是因为可执行文件的入口点通常不是 main - 在调用 main 之前发生了相当多的活动,与环境设置和其他事情有关(以及main 退出后的一些拆解内容,例如您的 atexit 处理程序。

换句话说,虽然main 函数可能是您的 C 程序开始的地方,但这与您的可执行文件的开始位置相同。

作为一个例子,在 Linux 中,ELF 可执行文件格式在标头块的 e_entry 字段中包含一个入口点地址,这是程序加载器在准备好运行可执行文件时跳转到的位置。

设置它通常发生的情况是,您(隐式)链接一些启动代码,如crt0,并且链接器使用已知符号的地址填充e_entry 字段。其中的一个例子是(来自该链接,对 cme​​ts 稍作修改):

.text
.globl _start
_start:                       # Entry point known to linker.
    xor %ebp, %ebp            # RBP <- 0, mark end of stack frames.
    mov (%rsp), %edi          # Get argc from stack (implicitly
                              #   zero-extended to 64-bit).
    lea 8(%rsp), %rsi         # Take address of argv from stack.
    lea 16(%rsp,%rdi,8), %rdx # Take address of envp from stack.
    xor %eax, %eax            # Per ABI and compatibility with icc.

    call main                 # Three args %edi/%rsi/%rdx (first
                              #   two are C standard).

    mov %eax, %edi            # Effectively set up _exit(main()).
    xor %eax, %eax            # Per ABI and compatibility with icc.
    call _exit                # Terminate the program.

您可以在main 调用的任何一侧看到启动和拆除的事情,这为您提供了一个可能的解决方案。

通过创建您的自己的 crt0,将文本 main 替换为您想要调用的任何内容,并确保链接器使用 您的 crt0 而不是默认一个,你可以让它调用你想要提供的任何函数作为主函数。


但是,除了获得工作保障或在您的同事找不到您的代码从哪里开始时惹恼您的同事之外,您从能够使用任意命名的 main 函数中获得什么并不是很清楚 :-)

如果它是一种教育性的东西,那很好 - 我只是不会在现实世界中这样做。

【讨论】:

    【解决方案3】:

    有一个构建可执行共享库的解决方案,您可以使用另一个函数作为入口点来构建程序。

    代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    const char __invoke_dynamic_linker[] __attribute__ ((section (".interp"))) 
        = "/lib/ld-linux.so.2";
    void fun()
    {
        printf("This is fun./n");
        exit(0);
    }
    

    然后将你的程序构建为共享库,并指定 func 作为入口点:

    $ gcc -fpic -shared -o fun.so -Wl,-e,fun fun.c
    $ ./fun.so
    

    这种方式的问题是 func 不能像我们在 main 函数中那样有普通的参数,这是因为我们没有 c 库来初始化 main 参数的东西。

    【讨论】:

    • 您的建议似乎比问题更模糊。你的意思是说入口函数应该在动态链接库中,这样才能通过名字查到它的地址?
    • @GeorgeSkoptsov 它不需要是动态链接库,只有当您不需要删除符号信息或者您可以硬编码以将参数与某些已知函数符号进行比较时,它才可以在程序本身中.我认为 Manu 只是想让程序调用不同的函数。
    猜你喜欢
    • 1970-01-01
    • 2011-04-27
    • 2016-05-21
    • 2019-12-22
    • 1970-01-01
    • 1970-01-01
    • 2015-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多