Моя проблема следующая:
Я пытаюсь написать встроенное приложение, которое должно иметь собственный сценарий компоновщика (с использованием компилятора / компоновщика arm-none-eabi-gcc).
Встроенный загрузчик загружает двоичный файл и запускается с адреса 0x8000, поэтому мне нужен специальный скрипт компоновщика, который позволяет мне поместить желаемую функцию запуска в этот адрес. Код скрипта следующий:
MEMORY
{
ram : ORIGIN = 0x8000, LENGTH = 0x1000
}
SECTIONS
{
.start : { *(.start) } > ram
.text : { *(.text*) } > ram
.bss : { *(.bss*) } > ram
}
Имея это то, что я хочу сделать сейчас, это иметь функцию, которая будет вставлена в раздел .start так, чтобы она находилась в начале 0x8000. Для этого в моей библиотеке я использую следующую функцию:
__attribute__((section(".start"))) void notmain() {
main();
}
Кажется, это работает нормально, но позже я свяжу эту библиотеку с функцией notmain
с проектом, который определяет функцию main()
. В процессе связывания я вижу, что раздел .start
больше не существует, и символ notmain
полностью отсутствует. Когда я перемещаю функцию notmain из библиотеки (в проект), все в порядке.
Насколько я понимаю, этот компоновщик видит, что раздел .start вообще не используется в моем приложении, что заставляет его пропускать все разделы. Я уже пробовал добавить несколько атрибутов в функцию notmain, например (__attribute__((used)) __attribute__((externally_visible))
), но это тоже не сработало (notmain все еще отсутствует в окончательном двоичном файле).
Исходный код CMake следующий:
** Проект **
project(AutomaticsControlExample)
enable_language(ASM)
set(CMAKE_CXX_STANDARD 14)
set(SOURCES main.cpp PID.hpp)
set(DEPENDENCIES RPIRuntime PiOS)
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} ${DEPENDENCIES})
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_OBJDUMP} -D ${PROJECT_NAME}
COMMAND ${CMAKE_OBJDUMP} -D ${PROJECT_NAME} > ${PROJECT_NAME}.list
COMMAND ${CMAKE_OBJCOPY} ${PROJECT_NAME} -O binary ${PROJECT_NAME}.bin
COMMAND ${CMAKE_OBJCOPY} ${PROJECT_NAME} -O ihex ${PROJECT_NAME}.hex)
** Библиотека **
project(RPIRuntime)
enable_language(ASM)
set(CMAKE_CXX_STANDARD 14)
set(LINKER_SCRIPT memmap)
set(LINKER_FLAGS "-T ${CMAKE_CURRENT_SOURCE_DIR}/${LINKER_SCRIPT}")
set(SOURCES
notmain.cpp
assert.cpp)
add_library(${PROJECT_NAME} STATIC ${SOURCES})
target_link_libraries(${PROJECT_NAME} ${LINKER_FLAGS})
Мой вопрос: есть ли способ запретить компоновщику пропускать ссылку на раздел .start?
1 ответ
Как вы знаете, статическая библиотека - это ar
архив объектных файлов.
Предположим, что libfoobar.a
содержит только foo.o
и bar.o
. Связь:
g++ -o prog a.o foo.o bar.o # A
не то же самое, что ссылка:
g++ -o prog a.o -lfoobar. # B
Компоновщик безоговорочно использует каждый объектный файл в последовательности связывания, поэтому в случае A
он связывает a.o
, foo.o
, bar.o
в prog
.
Компоновщик не безоговорочно потребляет каждый объектный файл, который является членом статическая библиотека в последовательности связывания. Статическая библиотека - это способ предложить компоновщик - набор объектных файлов, из которых можно выбрать нужные.
Предположим, что a.o
вызывает функцию foo
, которая определена в foo.o
, и что a.o
не ссылается ни на что, определенное в bar.o
.
В этом случае компоновщик безоговорочно связывает a.o
с prog
, после чего prog
содержит неопределенную ссылку на foo
, для которой компоновщику требуется определение. Затем он достигает libfoobar.a
и проверяет архив (по его индексу, обычно), чтобы узнать, определяет ли какой-либо член архива foo
. Он обнаруживает, что foo.o
делает так. Таким образом, он извлекает foo.o
из архива и связывает его. Не нуждается в определениях для любых символов, определенных в bar.o
, поэтому bar.o
не добавляется к связи. В linkage B
точно такой же, как:
g++ -o prog a.o foo.o
Предположим, с другой стороны, что a.o
вызывает bar
, который определен в bar.o
, и не ссылается ни на что, определенное в foo.o
. В этом случае связь B
точно так же, как:
g++ -o prog a.o bar.o
Итак, объектный файл, который вы вставляете в статическую библиотеку для связывания с ваш исполняемый файл никогда не будет связан по умолчанию, если он не предоставляет определение по крайней мере для одного символа, на который есть ссылка, но не определенный в объектном файле это уже было связано.
Ваша функция notmain
не упоминается в единственном объектном файле main.o
, который вы явно связываете свою программу. Следовательно, когда main.o
связан с вашей программой, программа не содержит неопределенной ссылки на notmain
: компоновщик не требует определения of notmain
- он никогда не слышал о notmain
- и не будет связывать какой-либо объектный файл из статической библиотеки, чтобы получить определение notmain
. В этом нет ничего делать с разделами ссылок.
Связывая обычную программу со статическими библиотеками, вы, естественно, делаете это так:
g++ -o prog main.o x.o ... -ly -lz ....
Где один из файлов *.o
, скажем main.o
- это объектный файл, который определяет функцию main
. Ты никогда поместите main.o
в одну из статических библиотек. Это потому, что в обычной программе main
не вызывается ни в одном из других объектных файлов, на которые вы явно ссылаетесь, поэтому, если main.o
был в одной из ваших библиотек, связь:
g++ -o prog x.o ... -ly -lz ...
Не нужно было бы находить определение main
в любом из -ly -lz ...
, и никакого определения из main
будут связаны.
То же самое и с вашим notmain
. Если вы хотите, чтобы он был связан, вы можете сделать одно из: -
Добавьте
-Wl,--undefined=notmain
в параметры связи (заменивnotmain
на искаженное имяnotmain
для C ++). Это заставит компоновщик предположить, что у него есть неопределенная ссылка наnotmain
, даже если она не видела.Добавьте команду
EXTERN(notmain)
в свой сценарий компоновщика (снова с искажением для C ++). Это эквивалентно 1 .Явно свяжите объектный файл, который определяет
notmain
. Не помещайте его в статическую библиотеку.
3 - это именно то, что вы сделали, когда обнаружили, что:
Когда я перемещаю функцию notmain из библиотеки (в проект), все в порядке.
Однако для 3 вам не нужно компилировать notmain.cpp
в своем проекте и любом другом проект, которому требуется notmain.o
. Можно собрать самостоятельно, установить в /usr/local/lib
и явно добавить /usr/local/lib/notmain.o
в увязка вашего проекта. Это будет следование примеру самого GCC, который явно связывает файлы запуска crt*.o
обычной программы, просто добавляя их абсолютные имена для связи, например
/usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/crti.o
...
/usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/crtn.o
Похожие вопросы
Новые вопросы
gcc
GCC - это коллекция компиляторов GNU. Это де-факто стандартный компилятор для C, C ++, Go, Fortran и Ada в Linux, а также поддерживает многие другие языки и платформы.