Мой загрузчик не может быть скомпилирован с gcc 4.6 и 4.7... только 4.5

Я создал свой загрузчик до 2 лет в Debian Squeeze/stable с gcc 4.5. Сейчас в Debian wheezy/sid не может быть скомпилирован с 4.6 и 4.7, потому что создает из них большие секции, которые я ожидаю получить конечный двоичный файл вручную. Это не проблема для меня сейчас, так как в Debian Wheezy/Sid gcc 4.5 все еще там, но я хотел бы сделать возможным компиляцию с gcc 4.6 и 4.7.

Я создаю последний бинарный файл так:

исходные файлы скомпилированы с:

gcc-4.5 -Wall -O3 -c -m32 -I. -o assemblybin-objects/vga_pm.S.o vga_pm.S

связано с:

ld -nostdlib -T binary.ld assemblybin-objects/vga_pm.S.o ... and other objects here ... -o bootloader.bin

содержимое binary.ld:

OUTPUT_FORMAT("binary","binary","binary")
OUTPUT_ARCH(i386)

SECTIONS
{
. = 0;
.bootloader : {
    . = 0x600;
    *(.bootstrap);
    . = 0x7fa;
    BYTE(0x11);
    BYTE(0x33);
    BYTE(0x55);
    BYTE(0x77);
    BYTE(0x55);
    BYTE(0xaa);
    _bootstrap_end = .;
    . = 0x800;
    *(.sysinit);
    _sysinit_end = .;
    . = 0x1000;
    *(.pages);
    _pages_end = .;
    . = 0x5000;
    *(.sysconf);
    *(.presystem);
    *(.system);
    *(.library);
    *(.text);
    *(.data);
    *(.bss);
    *(.rodata);
    *(.rodata.*);
    . = 0xeffc;
    BYTE(0x11);
    BYTE(0x33);
    BYTE(0x55);
    BYTE(0x77);
    _system_end = .;
}

. = ASSERT(_bootstrap_end <= 0x800,"Bootstrap section big!");
. = ASSERT(_sysinit_end <= 0x1000,"Sysinit section big!");
. = ASSERT(_pages_end <= 0x5000,"Pages section big!");
. = ASSERT(_system_end <= 0xf000,"System initialization section big!");
}

наконец-то создал финальный двоичный файл с dd.

Я видел, что при компиляции с gcc 4.6 и 4.7 компоновщик добавляет несколько байтов (250-300) в начале bootloader.bin.

Я использую ld из binutils 2.22 и готовлю по своим собственным рецептам для процесса сборки.

Мои актуальные вопросы:

В чем различия между этими версиями компилятора gcc, и они создают большие разделы или инструктируют компоновщик через объектные файлы elf добавить эти байты в начале файла bootloader.bin?

Есть ли какой-либо аргумент командной строки для gcc 4.6 и/или 4.7, который отключит функцию, которая может создавать большие секции, чем gcc 4.5, или уберет инструкции, которые говорят компоновщику добавить эти байты в начале Файл bootloader.bin?

редактировать 17-08-2012: Я сейчас немного занят, но скоро я обновлю результаты моих тестов.

Ответ @strnk и @Dan Aloni: когда я увидел эту проблему, первым делом я исключил бесполезные разделы, но результаты те же... Я думаю, потому что bootloader.bin - это простой двоичный файл со связанным кодом необходимого кода. разделы в правильном положении, как указывал компоновщик, без имен разделов, информации о перемещении и отладке и символов... Файл bootloader.bin не является объектным файлом elf.

Пожалуйста, рассмотрите изменения актуальных вопросов. Спасибо за все... я скоро вернусь

редактировать 31-08-2012: Хорошо, ребята, спасибо за вашу помощь. Ответ, данный @Dan Aloni и выполненный с ldscript, как показывает @strnk

/DISCARD/ : {
    *(.eh_frame)
    *(.eh_frame_hdr)
}

после утверждений.

Ответ 1

Скомпилировав тривиальный файл C с указанными вами флагами между gcc-4.5 и gcc-4.6 и используя objdump -h для проверки вывода, кажется, что раздел .eh_frame введен в gcc-4.6.

ld script, который вы предоставили, не заботится об этом разделе, и, вероятно, это должно произойти. Вы можете использовать strip -R .eh_frame -R .eh_frame_hdr, чтобы удалить этот раздел и другие из объектных файлов до связывания.

В любом случае, поскольку компоновщик одинаковый для обеих версий gcc, objdump -h в объектных файлах намекает на разницу, которая вызывает эту проблему.

Ответ 2

Есть ли какой-либо аргумент командной строки, который отключит функцию, которая может создавать большие разделы

Да: если вам нужен размер, вы должны построить с помощью -Os. -O3 явно включает оптимизацию, которая может привести к увеличению размера кода. Поскольку загрузчик выполняется один раз, использование -O3 для него почти наверняка неверно.

Edit:

"Оптимизация в сборке бессмысленна...
... и другие объекты здесь..."

Является ли весь ваш код в сборке? Если это так, уровень оптимизации действительно бессмыслен, но тогда вы должны просто сравнить результат из readelf -S vga_pm.S.o, построенный с обоими компиляторами, и посмотреть, какие именно разделы отличаются.

Но более вероятно, что некоторые из ваших объектов не собраны, и в этом случае разница между -O3 и -Os будет весьма значимой.

Ответ 3

GCC добавляет некоторые нежелательные разделы отладки в свой двоичный вывод (используйте objdump -h <file>, чтобы увидеть их), я обычно помещаю те, которых я не хочу, в правило /DISCARD/ в моих ld-скриптах, чтобы избавиться от них:

/DISCARD/ : {
        *(.debug_*)
        *(.note*)
        *(.indent)
        *(.comment)
        *(.stab)
        *(.stabstr)
        *(.eh_frame)
}

Ответ 4

Возможно, вы захотите отметить, что вы вообще не используете GCC.

vga_pm.S, судя по расширению файла, является источником ассемблера, содержащим директивы препроцессора, поэтому вам нужен препроцессор cpp для его преобразования в предварительно обработанный (.s) источник. Обратите внимание, что сборщик GNU (as) имеет все необходимые исходные директивы, например. для включения файла, чтобы сделать этот шаг ненужным.

"Компиляция".s источник в .o объектный файл также не требует GCC, так как это можно сделать с помощью as напрямую (который является частью пакета binutils).

Затем вы используете ld для связывания объектного файла в двоичном формате. Опять же, ld является частью пакета binutils.

Использование GCC в качестве внешнего интерфейса смущает проблему, имеет мало пользы и может оказаться в корне вашей проблемы. На всякий случай, вы сказали нам, какие версии GCC вы использовали, но вы не сказали нам, какие версии binutils вы использовали...

Я рекомендую не зависеть от инструментов, которые не являются строго необходимыми, чтобы максимально упростить процесс сборки. В этом случае удалите GCC с шага сборки загрузчика.