В своем последнем блоге я все еще пытался сделать что-то в Linux, не имея ни малейшего представления о реализации Mac OS X, а также неудачную попытку Microsoft MSVC. С тех пор многое изменилось. В этом блоге я продолжу с того, что остановил.

Реализация Linux

Исходя из моих предыдущих исследований и попыток запустить main () в потоке HPX, я наконец реализовал его, и он также был успешно интегрирован в HPX. Реализация состоит из использования флага компоновщика -Wl, -wrap для обертывания __libc_start_main и изменения точки входа в программу. Подробнее об этом можно прочитать в моих предыдущих блогах.

Реализация Mac OSX

Позаботившись о моей реализации в Linux, я начал искать способы реализовать то же самое в Mac OSX. Сначала нам нужно понять, почему моя реализация Linux недостаточно переносима, и нам нужно реализовать ее по-разному для разных ОС.

  • В каждой ОС есть свой компоновщик с разными флагами компоновщика. Флаг компоновщика -wrap недоступен как в Windows, так и в Mac OSX.
  • Mac OSX использует собственную версию libc, а __libc_start_main - это функция libc, предоставляемая glibc. Поэтому Mac OSX не содержит той самой функции, к которой можно было бы подключиться.

Это потребовало альтернативного способа изменения точки входа в программу. Именно тогда я наткнулся на флаг компоновщика -e. Это изменяет точку входа программы на точку входа, определяемую пользователем, в отличие от main (). Хотя этот флаг был доступен и в Linux, от него не было пользы, так как он изменил точку входа ELF с _start на точку входа, определяемую пользователем. Это означало бы, что мне пришлось сначала реализовать _start, а затем полностью создать стек функций. Очевидно, что -wrap предоставил мне лучшие альтернативы.

Все станет яснее на следующем примере:

Создайте файл (назовем его link.cpp) и скопируйте следующий код:

Теперь давайте создадим еще один файл (назовем его main.cpp), который будет содержать нашу основную функцию.

Теперь откройте терминал и напишите следующие команды:

$ clang++ -c -o link.cpp.o link.cpp
$ clang++ -c -o main.cpp.o main.cpp
$ clang++ -Wl,-e,_before_main -o result link.cpp.o main.cpp.o

Из приведенных выше команд мы видим использование флага компоновщика -e. Запуск сгенерированного исполняемого файла должен дать следующий результат:

$ ./result
before_main
main

Из вышеприведенного вывода совершенно ясно, что точка входа была изменена с main на before_main. Я использовал этот метод для выполнения всех инициализаций, необходимых для запуска среды выполнения HPX.

Мне удалось его успешно реализовать, и в настоящее время мои наставники проверяют его.

А теперь перейдем к концу окна.

Реализация MSVC

После того, как мой наставник не смог достичь ожидаемого результата с помощью MSVC, я связался с командой MSVC. Я разделял свои сомнения и искал способы их реализовать.

К сожалению, MSVC не обеспечивает элегантного способа инициализации системы времени выполнения HPX. После обмена несколькими электронными письмами мы пришли к двум способам реализации.

Первый метод

Повторная реализация mainCRTStartup, которая является точкой входа для файла exe. Реализация функции в отдельном файле, любая компиляция ее в файл obj и дальнейшее связывание во время компоновки обеспечат выполнение моей реализации mainCRTStartup, а не реализации MSVC. .

Хотя этот метод представляет собой элегантное решение, существует ряд серьезных проблем с обслуживанием, которые необходимо решить. Во-первых, это вопрос переносимости между разными архитектурами. Необходимо переписать код, специфичный для каждой архитектуры. Во-вторых, довольно часто меняется код функции. Это будет означать, что мне придется сохранить многократную реализацию функции для разных версий компилятора MSVC.

В настоящее время я пытаюсь подробно изучить этот метод, чтобы понять его осуществимость.

Второй метод

Это предполагает использование #pragm init_seg. Это может позволить пользователям вводить код на различных этапах программы. Хотя на первый взгляд это выглядит прибыльным, мы не можем заставить его запускаться после того, как были созданы все определенные пользователем глобальные объекты. Однако мы можем бежать, бежать раньше него.

При запуске до того, как все глобальные объекты, использующие hpx_start, зарегистрируют поток ядра с потоком HPX, я все равно не смогу использовать все функции, которые он предоставляет. С учетом сказанного, всегда можно использовать run_on_hpx_thread (), поскольку глобальные объекты и main зарегистрированы в системе времени выполнения HPX (но не работают в ней!). Этот метод аналогичен тому, что представлен в примере init_globally.

Я также глубоко изучаю этот метод.

Что дальше?

При реализации для Linux и Mac OSX у меня возникла идея создать специальную функцию init для библиотеки HPX. Если вы не знакомы с назначением функции init, то вкратце, она отвечает за инициализацию раздела .init_array, а также за вызов конструкторов глобальных объектов. По сути, он имеет дело со всеми инициализациями, относящимися к глобальным переменным и объектам области видимости. Если мы реализуем функцию init для HPX, тогда мы сможем иметь дело с некоторыми инициализациями глобальной области и запускать их в потоке HPX.

Именно на этом я сосредоточусь в будущем вместе с внедрением MSVC.

До следующего раза прощаюсь с вами!