如何找到我的程序的 main(...) 函数?

Posted

技术标签:

【中文标题】如何找到我的程序的 main(...) 函数?【英文标题】:How do I find my program's main(...) function? 【发布时间】:2009-03-05 12:03:38 【问题描述】:

我目前正在将一个包含数百个代码文件和依赖项的项目移植到几个第三方库到 Mac Os 上。我终于达到了程序编译没有警告或错误的地步,但它似乎没有执行我自己的 main 函数。

相反,它似乎执行了一些其他似乎属于第三方的主要功能。此函数将一些诊断数据写入控制台,然后退出:

(gdb) continue
Current language:  auto; currently c++
//
// This is an automatically generated file.
// Do not edit.
//

const unsigned short expTable[] =

    0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, 
...
    0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, 
;

Debugger stopped.
Program exited with status value:0.

我无法使用调试器找出这个 main 函数所在的位置,因为虽然堆栈跟踪似乎有效,但 gdb 没有为我显示每个堆栈条目的正确行号和文件名(请参阅 this unsolved question细节)。

搜索需要几分钟才能完成,但没有返回任何结果。

我的项目在其他库中使用 SDL,但我获得了 SDL_Main() 和潜在问题的奖励,并且在完美运行的 SDL 项目模板之上构建了我的项目。所以我很确定我自己的main函数是有效的。

您知道可能出了什么问题吗?我目前对如何查找和删除流氓主要功能一无所知。

谢谢,

阿德里安

编辑: 正如我刚刚发现的,我在使用字符串“这是一个自动生成的”搜索文件文件时犯了一个错误。我刚刚发现了几十个具有相同字符串的文件,它们都属于我正在使用的第三方库之一 FreeImage。因此,问题似乎与 FreeImage 有关,但我仍然不确定如何继续,因为我已将 Freeimage 编译为包含 MacOs makefile 的库并且仅包含该库。我会尝试重建一个新版本的 FreeImage 并查看它是否解决了我的问题。

【问题讨论】:

我假设您的流程类似于:gdb foob main r 正确吗? 我通常通过 XCode 运行 gdb,但我尝试按照您的描述直接使用 gdb 并得到相同的结果。 【参考方案1】:

它可能是在调用 main() 之前失败的静态对象的初始化程序吗?

【讨论】:

即全局对象的构造函数(对初学者)。 +1 很有可能,但是代码文件有几百个,我怎么知道? 在调试器中运行它。在 terminate() 中放置一个断点。查看从哪里调用终止。【参考方案2】:

二进制文件中有几个主要的吗?尝试在其上使用nm(这应该是不可能的,因为ld 不会与重复链接,而是进入动态库并在那里查找_main

nm a.out | grep -5 _main

这应该在二进制 a.out 中找到的任何 _main 之前和之后给出 5 行

如果您有多个,请查看周围的符号以提示它们位于哪些部分...

下一步可以对使用的每个动态库执行相同的操作。要获取使用的动态库的列表,请使用 otool

otool -L a.out

【讨论】:

【参考方案3】:

我不知道如何找到另一个,但您可以明确指定自己的入口点并使另一个不使用。您可以使用 GNU 链接器 ld -e 选项来设置您的入口点。

-e 条目

--entry=entry

使用 entry 作为开始执行你的显式符号 程序,而不是默认入口点。如果没有符号 bol 命名条目,链接器将尝试将条目解析为数字, 并将其用作入口地址(该数字将被解释 以 10 为基数;您可以使用前导 0x 作为基数 16,或前导 0 以 8 为基数)。

对于未来的读者,如果您在 Windows 中遇到此问题。等效的链接器选项是/ENTRY。

【讨论】:

【参考方案4】:

您是否尝试通过nm 运行您的可执行文件?或许能给你一些提示。我认为不可能将一个程序与多个名为main() 的全局可见函数链接起来,不知道这是如何实现的。

【讨论】:

我刚做了。只定义了一个主函数。我还注意到 nm 将 main 函数定位在与 gdb 不同的地址。它可能是正确的地址,但我不确定如何验证。【参考方案5】:

查看您包含的头文件,看看是否没有将main 重新映射到其他内容的定义。这是确保首先调用库的主要功能以进行某些设置的老技巧。一般来说,它最终会通过引用重新定义的值来调用你的 main 函数。

【讨论】:

我知道 SDL 会这样做(这就是我对 SDL_Main() 的意思,而且似乎 FreeImage 也这样做。我会尝试在 FreeImage 源中找到类似的内容。 【参考方案6】:

快速破解:

readelf -s -w my_bin_file > temp.txt

打开 temp.txt,搜索 main(在一列中带有 FUNC) 向上直到找到第一个 FILE 列 - 这是带有链接 main 的文件。

编辑:这仅适用于 GNU Unix 风格和朋友。 OS X 使用 Mach-O 格式,而不是 ELF。

【讨论】:

这看起来不错,但我使用的是 MacOS X,找不到任何 readelf 源。我猜 readelf 通常预装在 linux 发行版上? 是的,它带有 linux 发行版。我现在无法使用 Mac。你可能可以用 fink 安装它。 我的错误。 OS X 不使用 ELF。你可以看看这篇文章:0xfe.blogspot.com/2006/03/how-os-x-executes-applications.html我还没看,但它可能有有用的信息。 仅供参考:在 Mac 上,您可以使用 nm 或 otool,正如 epatel 在此处的另一个答案中概述的那样。 感谢您的提示。 +1 为 epatel【参考方案7】:

我知道在 C 中,您可以在 main 函数之前调用不同的入口点,这可能是一个想法。代码通常如下所示:

void __attribute__ ((constructor)) my_main(void);

也许你可以在你的代码中搜索类似的东西。

在 C 中,也有不同的方法来捕获主函数并在“真正的”主函数之后调用它。为了“准备”环境、调度程序和类似的东西,一些线程库有这种 hack。

这并不是很有用,但这可以解释为什么你的 main 根本没有被调用。

希望这会有所帮助!

【讨论】:

【参考方案8】:

另一个注释。

WxWidgets 也定义了自己的main

来自here

在所有程序中都必须有一个“main”函数。 wxWidgets下main是使用这个宏实现的,它创建一个应用实例并启动程序。

IMPLEMENT_APP(MyApp)

【讨论】:

【参考方案9】:

看起来您可以将一个名为b44ExpLogTable.cpp 的文件编译到您的二进制文件或某个第三方库中。看起来那个小程序是生成一个 exp() 表,但不知何故被导入到您的项目中

见this 和FreeImage sources 中的这个

【讨论】:

【参考方案10】:

生成地图文件。大多数程序实际上并不是从 main 开始的。来自 GCC 的 mapfile 应该告诉您 __start 或 __executable_start 的地址,您应该能够闯入并逐步查看导致程序退出的原因。

【讨论】:

我认为他的意思是您将“-map my_map_file”添加到最终链接命令中。如果使用“c++”或类似的,你可以使用“-Xlinker -map -Xlinker my_map_file” 即使您不能使用 GDB(您可以使用,但它与您的源代码不相符)...每当您想查看可执行文件中的内容时,您都会生成一个映射文件。每当您想查看正在发生的事情时,您都会中断程序输入并逐步执行。即使你必须在汇编中这样做。

以上是关于如何找到我的程序的 main(...) 函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何防止我的程序出现此分段错误(核心转储)?

成员函数的 C++ GDB 断点

profiler:我能找到调用我的函数的东西吗?

无法在“main”中找到应用程序对象“app”-Heroku CLI

我的程序在进入main()函数之前退出

如何将我的 main() 函数输出为 CSV 文件