Ссылка на внешние глобальные переменные с треском проваливается

#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 сообщает о трех глобальных переменных, имена которых не требуют пояснений:

  1. _binary_B_start
  2. _binary_B_end
  3. _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. Фактически это константа со значением, заранее определенным во время компиляции. Для этого нет причин занимать хранилище. И то, что вы видите выше, является одним из способов кодирования таких постоянных значений в объектных файлах.