Это проблема связывания, а не сборки.
Если вы попросите GCC (или лучше, ld
) показать скрипт связывания с -Wl,--verbose
, вы обнаружите строку
.got.plt : { *(.got.plt) *(.igot.plt) }
, которая инструктирует компоновщика принять все.got.plt
разделов, в порядке совпадения .
Обычно компоновщик размещает файлы и разделы, совпадающие с подстановочными знаками, в порядке, в котором они видны при ссылке.
С здесь
Поскольку вы компилируете с помощью CRT, что подразумевает его собственные объектные файлы, ваши объектные файлы идут после него.
Я не знаю, стандартизирован ли этот порядок или что-то в разных версиях GCC, я думаю, что он может быть изменен в любое время.
Вы должны быть в состоянии подтвердить, что добавление -v
и -Wl,-M
в командную строку GCC;первая покажет вам, как GCC вызывает компоновщик, для меня это:
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. /tmp/ccref9XH.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o
Это трудно увидеть, но объектный файл test.s
равен /tmp/ccref9XH.o
(собрал несколько строк выше в полном объемеoutput) и некоторые объектные файлы CRT передаются в collect2
перед ним.
Второй вариант покажет отображение между секциями вывода и ввода:
.got.plt 0x0000000000601000 0x25
*(.got.plt)
.got.plt 0x0000000000601000 0x20 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o
0x0000000000601000 _GLOBAL_OFFSET_TABLE_
.got.plt 0x0000000000601020 0x5 /tmp/ccisjx2P.o
0x0000000000601024 main
, показывая, что секция crt1.o
.got.plt
стоит первой (обратите внимание, что вы оставили main
в разделе .got.plt
).
Я не нашел удовлетворительного способа преодолеть это.
Одна из возможностей - скопировать скрипт компоновщика и изменить определение .got.plt
на что-то вроде:
.got.plt : { *(.got.plt.pre) *(.got.plt) *(.igot.plt) }
тогда вы можете поместить свои данные в .got.plt.pre
(ПРИМЕЧАНИЕ: не проверено).
Но это кошмар для удобства обслуживания.
Я пытался поиграть с --sort-section=name
из ld
, который добавляет команду SORT
к каждому разделу подстановочных знаков, вводимому в скрипт компоновщика.
Это должно выровнять разделы в соответствии с файлом "или имя раздела".
После нескольких попыток я заглянул в источник, и это фактически только название раздела, поэтому здесь оно бесполезно.
Я вернулся к --sort-section=alignment
.
Сначала файл test.s
должен быть собран в объектный файл с gcc -c test.s -o test.o
.
Проблема здесь заключается в создании раздела .plt.got
в test.o
с большим выравниванием, чем 8 (тот, который используется в других .plt.got
разделах).
Я проверил objcopy
, но ничего не нашел, может быть, кто-то найдет подходящую команду?
I 'мы лично пропатчили файл test.o
с помощью шестнадцатеричного редактора, придав этому разделу 32-байтовое выравнивание.
Затем при вызове gcc -Wl,--sort-section=alignment test.o -o test
получается ELF с разделом test.s
перед остальными.
Однако это громоздкое решение, хотя можно легко разработать инструмент для изменения выравнивания раздела ELF, который я надеюсь найти существующий.
Извините, что ни один из вышеперечисленных вопросов не является правильным ответом на вашу проблему.