#c #gcc #linker #binary #ld
#c #gcc #компоновщик #двоичный #ld
Вопрос:
Я пытаюсь встроить двоичный файл B
в исполняемый файл A
во время компоновки в Linux (64bit).
B
это простой текстовый файл…
Hi, I'm a text file in plain ASCII.
…который превращается в перемещаемый объект с ld -r -bbinary -oB.o B
. Он symtab
сообщает о трех глобальных переменных, имена которых не требуют пояснений:
_binary_B_start
_binary_B_end
_binary_B_size
Это A.c
…
#include <stdio.h>
extern const size_t _binary_B_size;
int main(int argc, char * * argv)
{
printf("size: %zun", _binary_B_size);
return 0;
}
…который скомпилирован и связан с B.o
: gcc -oA A.c B.o
.
К сожалению, как только исполняемый файл A
пытается получить доступ _binary_B_size
, он внезапно завершается с помощью SIGSEGV
.
Что я делаю не так?
Ответ №1:
По-видимому, вы неправильно понимаете семантику _binary_B_size
. Это не size_t
значение lvalue, как вы, кажется, полагаете. Это абсолютно позиционированный раздел нулевого размера (метка), адрес которого равен размеру ваших двоичных данных blob. Попробуйте objdump -t
свой файл, и вы увидите *ABS*
в соответствующем столбце.
Таким образом, правильное использование было бы
extern unsigned char _binary_B_size[];
int main()
{
printf("size: %zun", (size_t) _binary_B_size);
}
Вы также можете использовать end - start
метод и получить тот же результат
extern unsigned char _binary_B_start[];
extern unsigned char _binary_B_end[];
int main()
{
printf("size: %zun", (size_t) (_binary_B_end - _binary_B_start));
}
В принципе, основное соображение здесь заключается в том, что нет причин для _binary_B_size
быть size_t
значением lvalue. Фактически это константа со значением, заранее определенным во время компиляции. Для этого нет причин занимать хранилище. И то, что вы видите выше, является одним из способов кодирования таких постоянных значений в объектных файлах.