Hi,
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.
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).
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.
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.
-
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 namedmain()
, not sure how that manages to happen.Adrian Grigore : I just did. There is only one main function defined. I also noticed that nm locates the main function at a different address than gdb. It might be the right address, but I am not sure how to verify. -
Could it be an initializer for a static object that fails before your main() is called?
Martin York : i.e. The constructor of a global object (to the uninitiated). +1Adrian Grigore : Very well possible, but with a few hundred code files, how can I tell?Martin York : Run it in the debugger. Put a break point in terminate(). See where terminate gets called from. -
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.
-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).
For future readers, if you have this problem in Windows. The equivalent linker option is /ENTRY.
-
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.Adrian Grigore : I know that SDL does this (that's what I mean with SDL_Main(), and it would seem that FreeImage does so as well. I'll try to find something like this in the FreeImage sources. -
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.
edit: This only works on GNU Unix flavors and friends. OS X uses the Mach-O format, not ELF.
Adrian Grigore : This looks great, but I am using MacOS X and I could not find any readelf sources. I guess readelf usually comes preinstalled on with linux distros?Gilad Naor : Yes, it comes with linux distros. I don't have access to a Mac right now. You can probably install it with fink.claferri : with mac port, a port search readelf returns nothing.Gilad Naor : My mistake. OS X doesn't use ELF. You might check this article: http://0xfe.blogspot.com/2006/03/how-os-x-executes-applications.html I didn't read it yet, but it may have useful information.Craig S : FYI: On the Mac, you can use nm or otool, as epatel outlines in another answer here.Gilad Naor : Thanks for the tip. +1 for epatel -
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 :
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.
This is not really usefull but this may explain why your main isn't called at all.
Hope this helps!
-
Do you have several main in the binary? Try using
nm
on it. (it shouldn't be possible asld
won't link with duplicates, but go into the dynamical libs and look for_main
there)nm a.out | grep -5 _main
This should give 5 lines before and after any
_main
found in the binarya.out
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 -L a.out
-
Another note.
WxWidgets do also define their own
main
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.
IMPLEMENT_APP(MyApp)
-
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)See this and this in FreeImage sources
-
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.
Adrian Grigore : Unfortunately this doesn't work if the debugger is not working...epatel : I think he means that you add "-map my_map_file" to the final link command. If "c++" or similar is used you can use "-Xlinker -map -Xlinker my_map_file"Dan Olson : Even if you can't use GDB (which you can, it just doesn't line up with your source)... whenever you want to see what's in your executable you generate a map file. Whenever you want to see what's going on, you break on program entry and step through. Even if you have to do it in assembly.
0 comments:
Post a Comment