我的引导加载程序无法使用gcc 4.6和4.7 ...仅编译4.5

时间:2012-08-05 20:40:49

标签: linux gcc bootloader

我使用gcc 4.5在debian squeeze / stable下创建了我的引导加载程序2年。现在在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进行编译时,链接器会在bootloader.bin的开头添加一些字节(250-300)。

我正在使用ld 2.22中的binutils并使用我自己的食谱烹饪构建过程。

我的实际问题是:

gcc编译器的这些版本之间有什么区别,它们会生成更大的部分或指示链接器通过elf目标文件在bootloader.bin文件的开头添加这些字节吗

gcc 4.6和/或4.7是否有任何命令行参数会关闭可能产生比gcc 4.5更大的部分的功能,或删除那些说{链接器在bootloader.bin文件的开头添加这些字节?

编辑17-08-2012:这些天我很忙,但很快我会用我测试的结果更新。

回答@strnk和@Dan Aloni:当我看到这个问题时,我做的第一个就是排除无用的部分,但结果是一样的...我认为因为bootloader.bin是一个简单的二进制文件链接器指示在正确的位置链接所需部分的代码,没有部分名称,重定位和调试信息和符号...... bootloader.bin文件不是精灵对象文件。

请考虑实际问题的变化。 谢谢你的一切......我很快就会回来

编辑31-08-2012:好的,谢谢你的帮助。 @Dan Aloni给出的答案,并通过ld脚本完成@strnk显示

/DISCARD/ : {
    *(.eh_frame)
    *(.eh_frame_hdr)
}
断言后

4 个答案:

答案 0 :(得分:8)

通过使用您提供的标记编译一个简单的C文件,在gcc-4.5gcc-4.6之间,并使用objdump -h检查输出,似乎是.eh_frame部分在gcc-4.6中引入。

您提供的ld脚本不会处理该部分,而且可能应该这样做。在链接之前,您可以使用strip -R .eh_frame -R .eh_frame_hdr从目标文件中删除该部分和其他部分。

无论如何,由于两个gcc版本的链接器都是相同的,因此对象文件上的objdump -h将暗示导致此问题的差异。

答案 1 :(得分:4)

  

是否有任何命令行参数会关闭可能产生更大部分的功能

是:如果您关心尺寸,则应使用-Os进行构建。 -O3显式启用可能导致更大代码大小的优化。由于引导加载程序执行一次,因此使用-O3几乎肯定是错误的。

编辑:

  

&#34;装配优化毫无意义......
  ......以及其他物品......&#34;

汇编中所有代码?如果是这样,优化级别确实毫无意义,但是您应该能够简单地比较使用两个编译器构建的readelf -S vga_pm.S.o的输出,并确切地看到哪些部分是不同的。

但是,您的某些对象似乎更有可能在汇编中,在这种情况下,-O3-Os之间的差异将非常有意义。

答案 2 :(得分:3)

GCC在其二进制输出中添加了一些不需要的调试部分(使用objdump -h <file>来查看它们),我通常会在我的ld脚本的/DISCARD/规则中添加我不想要的那些摆脱他们:

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

答案 3 :(得分:2)

您可能需要注意您实际上并非使用 GCC

vga_pm.S,从文件扩展名来看,是包含预处理程序指令的汇编程序源,因此您需要cpp预处理程序将其转换为预处理(.s)源。请注意,GNU汇编程序(as)具有所有必需的本机指令,例如对于文件包含,不需要这一步。

“编译”.s源文件到.o目标文件也不需要GCC,因为这可以直接使用as(这是binutils包的一部分)来完成。

然后使用ld将目标文件链接到二进制文件。同样,ld是binutils包的一部分。

使用GCC作为前端混淆问题,几乎没有任何好处,实际上可能是您问题的根源。以防万一,您告诉我们您使用了哪些GCC版本,但是您没有告诉我们您使用了哪些 binutils 版本...

我建议不要依赖非严格必要的工具,以使您的构建过程尽可能简单。在这种情况下,从引导加载程序构建步骤中删除GCC。