Skip to content

Commit

Permalink
iOS: Use LC_MAIN to wrap user main() instead of mangling object files
Browse files Browse the repository at this point in the history
With iOS 6.0 and above the LC_MAIN load command is available, which allows
dyld to call the application entrypoint directly instead of going through
_start in crt.o. By passing -e to the linker we can change this entrypoint
to our wrapper that sets up the separate stack before entering the native
iOS runloop through UIApplicationMain. As before, we call the user's main()
from applicationDidFinishLaunching.

By using LC_MAIN instead of messing with the object files we open up the
possibility of generating Bitcode instead of object code, which can be
useful for link-time optimizations, either locally or by Apple.

Change-Id: If2153bc919581cd93dfa10fb6ff1c305b3e39a52
Reviewed-by: Richard Moe Gustavsen <[email protected]>
  • Loading branch information
Tor Arne Vestbø committed Jun 29, 2015
1 parent 7b0cb2f commit c937bbb
Show file tree
Hide file tree
Showing 4 changed files with 10 additions and 121 deletions.
34 changes: 6 additions & 28 deletions mkspecs/macx-ios-clang/features/qt.prf
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,12 @@ equals(TEMPLATE, app):contains(qt_depends, gui(-private)?) {
QTPLUGIN.platforms = -

!no_main_wrapper {
# We use ld to rename the _main symbol to _qt_main, so that we don't get a symbol clash
# with the _main we provide that calls UIApplicationMain. We need to make a copy of the
# original object file, as ld will not copy over DWARF debug information to the output
# file. Instead, it will inject a reference back to the original object file, so when
# Xcode runs dsymutil to make the final dSYM file it will still find the debug info
# for the object file that provided the original _main. This back-reference has the
# interesting side-effect of the debug information still referring to the original
# symbol name, so stack-traces will show both our wrapper main and the original
# user main as 'main', and adding a symbolic breakpoint for 'main' will break on
# both functions. Although a bit weird, it's a good thing, as the user will still be
# able to add symbolic breakpoints for 'main', not caring that the symbol is actually
# called 'qt_main' now.

macx-xcode {
objects_dir = "\"${OBJECT_FILE_DIR}-${CURRENT_VARIANT}\""
archs = "\"${ARCHS}\""
} else {
isEmpty(OBJECTS_DIR): \
objects_dir = .
else: \
objects_dir = $$shell_quote($$OBJECTS_DIR)
archs = $$shell_quote($$QMAKE_IOS_DEVICE_ARCHS $$QMAKE_IOS_SIMULATOR_ARCHS)
}

!isEmpty(QMAKE_PRE_LINK): \
QMAKE_PRE_LINK += ";"

QMAKE_PRE_LINK += $$shell_quote($$QMAKESPEC/rename_main.sh) $$objects_dir $$archs
# The LC_MAIN load command available in iOS 6.0 and above allows dyld to
# directly call the entrypoint instead of going through _start in crt.o.
# Passing -e to the linker changes the entrypoint from _main to our custom
# wrapper that calls UIApplicationMain and dispatches back to main() once
# the application has started up and is ready to initialize QApplication.
QMAKE_LFLAGS += -Wl,-e,_qt_main_wrapper
}
}

Expand Down
2 changes: 1 addition & 1 deletion mkspecs/macx-ios-clang/qmake.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ CONFIG += app_bundle reduce_exports incremental global_init_link
QMAKE_INCREMENTAL_STYLE = sublib

QMAKE_MACOSX_DEPLOYMENT_TARGET =
QMAKE_IOS_DEPLOYMENT_TARGET = 5.1.1
QMAKE_IOS_DEPLOYMENT_TARGET = 6.0

INCLUDEPATH += $$PWD/ios
DEFINES += DARWIN_NO_CARBON QT_NO_PRINTER QT_NO_PRINTDIALOG
Expand Down
78 changes: 0 additions & 78 deletions mkspecs/macx-ios-clang/rename_main.sh

This file was deleted.

17 changes: 3 additions & 14 deletions src/plugins/platforms/ios/qioseventdispatcher.mm
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ void printUsage()
bool debugStackUsage = false;
}

extern "C" int __attribute__((weak)) main(int argc, char *argv[])
extern "C" int qt_main_wrapper(int argc, char *argv[])
{
@autoreleasepool {
size_t defaultStackSize = 512 * kBytesPerKiloByte; // Same as secondary threads
Expand Down Expand Up @@ -233,18 +233,7 @@ void printUsage()
kJumpedFromUserMainTrampoline,
};

// We define qtmn so that user_main_trampoline() will not cause
// missing symbols in the case of hybrid applications that don't
// use our main wrapper. Since the symbol is weak, it will not
// get used or cause a clash in the normal Qt application usecase,
// where we rename main to qtmn before linking.
extern "C" int __attribute__((weak)) qtmn(int argc, char *argv[])
{
Q_UNUSED(argc);
Q_UNUSED(argv);

Q_UNREACHABLE();
}
extern "C" int main(int argc, char *argv[]);

static void __attribute__((noinline, noreturn)) user_main_trampoline()
{
Expand All @@ -263,7 +252,7 @@ static void __attribute__((noinline, noreturn)) user_main_trampoline()
qFatal("Could not convert argv[%d] to C string", i);
}

int exitCode = qtmn(argc, argv);
int exitCode = main(argc, argv);
delete[] argv;

qEventDispatcherDebug() << "Returned from main with exit code " << exitCode;
Expand Down

0 comments on commit c937bbb

Please sign in to comment.