如何找到程序的主要(...)功能?

时间:2021-03-22 07:33:07

I am currently porting a project with a few hundred code files and dependencies onto several third-party libraries to Mac Os. I've finally gotten to the point where the program compiles without warnings or errors, but it does not seem to execute my own main function.

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

Instead it seems to execute some other main function which seems to belong to a third party. This function writes some diagnostic-looking data to the console and exits afterwards:

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

(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.

I can't use the debugger to find out where this main function resides because, while the stack trace seems valid, gdb doesn't show me the correct line number and file name for each stack entry (See this unsolved question for details).

我无法使用调试器找出此主函数所在的位置,因为虽然堆栈跟踪似乎有效,但gdb没有向我显示每个堆栈条目的正确行号和文件名(有关详细信息,请参阅此未解决的问题)。

The search took several minutes to complete, but did not return any results.

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

My project is using SDL among other libraries, but I am award of SDL_Main() and the underlying problems and have built my project on top of a perfectly fine working SDL project template. So I am quite sure that my own main function is valid.

我的项目在其他库中使用SDL,但我获得了SDL_Main()和底层问题,并且在一个完美的工作SDL项目模板之上构建了我的项目。所以我很确定我自己的主要功能是有效的。

Do you have any idea what might be going wrong? I'm currently out of ideas on how to find and remove the rogue main function.

你知道可能出了什么问题吗?我目前没有关于如何查找和删除流氓主要功能的想法。

Thanks,

Adrian

EDIT: As I just found out, I made a mistake while searching file files with the string "This is an automatically generated". I just found several dozen files with the same string, all belonging to FreeImage, one of the third party libraries I am using. So, the problem seems to be related to FreeImage, but I am not still not sure how to proceed since I have compiled Freeimage as a library with the enclosed MacOs makefile and included only the library. I will try to rebuild a newer version of FreeImage and see it if that fixed my problem.

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

10 个解决方案

#1


Could it be an initializer for a static object that fails before your main() is called?

它可能是在调用main()之前失败的静态对象的初始值设定项吗?

#2


Do you have several main in the binary? Try using nm on it. (it shouldn't be possible as ld won't link with duplicates, but go into the dynamical libs and look for _main there)

你在二进制文件中有几个主要内容吗?尝试使用nm。 (它不应该是可能的,因为ld不会与重复链接,但进入动态库并寻找_main那里)

nm a.out | grep -5 _main

This should give 5 lines before and after any _main found in the binary a.out

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

If you have several, see the surrounding symbols for hints which parts they are in...

如果您有几个,请查看周围的符号以了解它们所在的部分...

Next step can be to do the same on each dynamic lib that is used. To get a list of the used dynamic libraries use otool

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

otool -L a.out

#3


I'm not sure how to find the other one, but you can specify your own entry point explicitly and make the other one unused. You can use the GNU linker ld -e option to set your entry point.

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

-e entry

--entry=entry

Use entry as the explicit symbol for beginning execution of your program, rather than the default entry point. If there is no sym- bol named entry, the linker will try to parse entry as a number, and use that as the entry address (the number will be interpreted in base 10; you may use a leading 0x for base 16, or a leading 0 for base 8).

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

For future readers, if you have this problem in Windows. The equivalent linker option is /ENTRY.

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

#4


Did you try running your executable through nm? It might be able to give you some hints. I wouldn't think it'd be possible to link a program with more than one globally visible function named main(), not sure how that manages to happen.

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

#5


Look through the header files that you include and see if there isn't a define that remaps main to something else. This is an old trick to ensure that a library's main function is called first to do some set up. Generally, it will eventually call your main function by referring to the redefined value.

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

#6


A quick hack:

一个快速的黑客:

readelf -s -w my_bin_file > temp.txt

Open temp.txt, search for main (with FUNC in one column) Go up until you find the first FILE column - this is the file with the linked main.

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

edit: This only works on GNU Unix flavors and friends. OS X uses the Mach-O format, not ELF.

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

#7


I know that in C, you can have a different entrypoint called before the main function, that could be an idea. The code usually looks like :

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

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

Maybe you can search for something like that in your code.

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

In C, there is also different ways to catch the main function and call it after the "real" main. Some threads library have this kind of hacks in order to "prepare" the environnement, scheduler and stuff like that.

在C中,还有不同的方法来捕获主函数并在“真实”主函数之后调用它。一些线程库有这种黑客攻击,以“准备”环境,调度程序和类似的东西。

This is not really usefull but this may explain why your main isn't called at all.

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

Hope this helps!

希望这可以帮助!

#8


Another note.

WxWidgets do also define their own main

WxWidgets也定义了自己的主要内容

From here

As in all programs there must be a "main" function. Under wxWidgets main is implemented using this macro, which creates an application instance and starts the program.

与所有程序一样,必须有“主要”功能。在wxWidgets下,main使用此宏实现,该宏创建应用程序实例并启动程序。

IMPLEMENT_APP(MyApp)

#9


It looks like you can have a file called b44ExpLogTable.cpp compiled into your binary or some thirdpart library. It looks like that little program is to generate a exp() table but has somehow come to be imported into your project(s)

看起来您可以将一个名为b44ExpLogTable.cpp的文件编译到您的二进制文件或某些第三方库中。看起来这个小程序是生成一个exp()表但是以某种方式导入到你的项目中

See this and this in FreeImage sources

在FreeImage源代码中查看此内容

#10


Generate a map file. Most programs don't actually start at main. A mapfile from GCC should tell you the address of __start or __executable_start, which you should be able to break in and step through to see what's causing your program to exit.

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

#1


Could it be an initializer for a static object that fails before your main() is called?

它可能是在调用main()之前失败的静态对象的初始值设定项吗?

#2


Do you have several main in the binary? Try using nm on it. (it shouldn't be possible as ld won't link with duplicates, but go into the dynamical libs and look for _main there)

你在二进制文件中有几个主要内容吗?尝试使用nm。 (它不应该是可能的,因为ld不会与重复链接,但进入动态库并寻找_main那里)

nm a.out | grep -5 _main

This should give 5 lines before and after any _main found in the binary a.out

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

If you have several, see the surrounding symbols for hints which parts they are in...

如果您有几个,请查看周围的符号以了解它们所在的部分...

Next step can be to do the same on each dynamic lib that is used. To get a list of the used dynamic libraries use otool

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

otool -L a.out

#3


I'm not sure how to find the other one, but you can specify your own entry point explicitly and make the other one unused. You can use the GNU linker ld -e option to set your entry point.

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

-e entry

--entry=entry

Use entry as the explicit symbol for beginning execution of your program, rather than the default entry point. If there is no sym- bol named entry, the linker will try to parse entry as a number, and use that as the entry address (the number will be interpreted in base 10; you may use a leading 0x for base 16, or a leading 0 for base 8).

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

For future readers, if you have this problem in Windows. The equivalent linker option is /ENTRY.

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

#4


Did you try running your executable through nm? It might be able to give you some hints. I wouldn't think it'd be possible to link a program with more than one globally visible function named main(), not sure how that manages to happen.

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

#5


Look through the header files that you include and see if there isn't a define that remaps main to something else. This is an old trick to ensure that a library's main function is called first to do some set up. Generally, it will eventually call your main function by referring to the redefined value.

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

#6


A quick hack:

一个快速的黑客:

readelf -s -w my_bin_file > temp.txt

Open temp.txt, search for main (with FUNC in one column) Go up until you find the first FILE column - this is the file with the linked main.

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

edit: This only works on GNU Unix flavors and friends. OS X uses the Mach-O format, not ELF.

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

#7


I know that in C, you can have a different entrypoint called before the main function, that could be an idea. The code usually looks like :

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

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

Maybe you can search for something like that in your code.

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

In C, there is also different ways to catch the main function and call it after the "real" main. Some threads library have this kind of hacks in order to "prepare" the environnement, scheduler and stuff like that.

在C中,还有不同的方法来捕获主函数并在“真实”主函数之后调用它。一些线程库有这种黑客攻击,以“准备”环境,调度程序和类似的东西。

This is not really usefull but this may explain why your main isn't called at all.

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

Hope this helps!

希望这可以帮助!

#8


Another note.

WxWidgets do also define their own main

WxWidgets也定义了自己的主要内容

From here

As in all programs there must be a "main" function. Under wxWidgets main is implemented using this macro, which creates an application instance and starts the program.

与所有程序一样,必须有“主要”功能。在wxWidgets下,main使用此宏实现,该宏创建应用程序实例并启动程序。

IMPLEMENT_APP(MyApp)

#9


It looks like you can have a file called b44ExpLogTable.cpp compiled into your binary or some thirdpart library. It looks like that little program is to generate a exp() table but has somehow come to be imported into your project(s)

看起来您可以将一个名为b44ExpLogTable.cpp的文件编译到您的二进制文件或某些第三方库中。看起来这个小程序是生成一个exp()表但是以某种方式导入到你的项目中

See this and this in FreeImage sources

在FreeImage源代码中查看此内容

#10


Generate a map file. Most programs don't actually start at main. A mapfile from GCC should tell you the address of __start or __executable_start, which you should be able to break in and step through to see what's causing your program to exit.

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