Как изменить точку входа для исполняемого файла mach-o для файла c ++? - PullRequest
0 голосов
/ 30 июня 2018

Я пытаюсь написать программу на C ++ без main. Можно ли изменить точку входа исполняемого файла mach-o на пользовательскую функцию (отличную от main())?

Если нет, то можно ли обернуть main для вызова моей версии main до вызова фактического C main?

Edit:

Я хочу, чтобы моя пользовательская функция вызывала C main. Если я дам ему атрибут конструктора или добавлю его в список ctor, то main будет вызван дважды. Я не хочу, чтобы это произошло.

P.S Я создаю исполняемые файлы в Mac OS X High Sierra с версией Clang 9.1.0

Ответы [ 3 ]

0 голосов
/ 30 июня 2018

Вы можете передать опцию -e <symbol name> компоновщику (ld), чтобы указать другую точку входа. Точка входа по умолчанию не main; это start, которое предоставляется crt1.o и которое, в свою очередь, вызывает main.

0 голосов
/ 30 июня 2018

Вы можете использовать опцию -e <symbol> ld, которую вы можете вызвать как -Wl,-e,_<symbol> из clang. Исторически, точка входа в программу была бы _start из crt0.o, однако это не было делом в Дарвине с Mac OS X 10.8 и iOS 6.0, где была введена команда загрузки LC_MAIN (заменившая LC_UNIXTHREAD ). «Старый» способ все еще можно использовать, но его необходимо явно включить с помощью флага компоновщика -no_new_main (который имеет аналог -new_main, если он вам когда-нибудь понадобится). Обязанность, некогда выполняемая crt0.o, была перенесена на динамический компоновщик /usr/lib/dyld, который может обрабатывать как LC_MAIN, так и LC_UNIXTHREAD при необходимости.

Итак, программа на C с main:

// t.c
#include <stdio.h>

int main(int argc, const char **argv)
{
    printf("test %i\n", argc);
    return 0;
}

Вы можете легко создать файл C ++, например так:

// t.cpp

extern int main(int, const char**);

extern "C" int derp(int argc, const char **argv)
{
    return main(0, (const char*[]){ (const char*)0 });
}

И скомпилируйте их с помощью clang++ -o t t.cpp -xc t.c -Wl,-e,_derp.
Обязательно объявите derp как extern "C" или укажите искаженный символ в командной строке.

Вы также можете проверить полученный исполняемый файл с помощью otool, чтобы убедиться, что он использует LC_MAIN вместо LC_UNIXTHREAD:

bash$ otool -l ./t | fgrep -B1 -A3 LC_MAIN
Load command 11
       cmd LC_MAIN
   cmdsize 24
  entryoff 3808
 stacksize 0
0 голосов
/ 30 июня 2018

Вы можете использовать _start()

Он устанавливает некоторые вещи, заполняет массив аргументов argv, подсчитывает, сколько там аргументов, а затем вызывает main. После возврата main вызывается exit.

Вот несколько ссылок:
https://stackoverflow.com/a/29694977/2302572
http://learningpearls.blogspot.com/2011/02/start-function-inside-c.html

...