10

我在 2 年前用gcc4.5 在 debian 挤压/稳定下创建了我的引导加载程序。现在在 debian wheezy/sid 中​​不能用 4.6 和 4.7 编译,因为从这些创建更大的部分,我希望手动生成最终的二进制文件。现在这对我来说不是问题,因为在 debian wheezy/sid 中​​,gcc4.5 仍然存在,但我希望能够使用gcc4.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

我看到当用gcc4.6 和 4.7 编译时,链接器在bootloader.bin.

我正在使用ld来自binutils2.22 的版本,并使用我自己的构建过程的食谱进行烹饪。

我的实际问题是:

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

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

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

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

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

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

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

在断言之后。

4

4 回答 4

8

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

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

无论如何,由于两个 gcc 版本的链接器是相同的,因此objdump -h在目标文件上会提示导致此问题的差异。

于 2012-08-16T04:20:29.543 回答
4

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

是的:如果你关心大小,你应该用-Os. -O3显式启用可能导致更大代码大小的优化。由于引导加载程序执行一次,使用-O3它几乎肯定是错误的。

编辑:

“装配中的优化是没有意义的……
还有这里的其他对象……”

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

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

于 2012-08-06T00:21:57.103 回答
3

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

/DISCARD/ : {
        *(.debug_*)
        *(.note*)
        *(.indent)
        *(.comment)
        *(.stab)
        *(.stabstr)
        *(.eh_frame)
}
于 2012-08-16T09:44:47.717 回答
2

您可能要注意,您实际上并没有使用GCC

vga_pm.S,从文件扩展名来看,是包含预处理指令的汇编源代码,所以你需要cpp预处理器把它变成预处理(.s)源代码。请注意,GNU 汇编器 ( as) 具有所有必要的本地指令,例如文件包含,以使此步骤变得不必要。

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

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

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

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

于 2012-08-16T10:15:38.030 回答