Мой загрузчик не может быть скомпилирован с 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 с шага сборки загрузчика.