10

gcc私は4.5の debian スクイーズ/安定版で 2 年前にブートローダーを作成しました。現在、debian では wheezy/sid を 4.6 および 4.7 でコンパイルできません。これは、最終的なバイナリを手動で生成することを期待して、これらからより大きなセクションを作成するためです。debian wheezy/sid には 4.5 がまだ残っているので、これは今のところ問題ではありませんが、 4.6 と 4.7gccでコンパイルできるようにしたいと考えています。gcc

次のような最終的なバイナリを生成します。

ソース ファイルは次のようにコンパイルされます。

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ます。

4.6 および 4.7でコンパイルするgccと、リンカがbootloader.bin.

私は2.22 以降を使用しており、ビルド プロセスには独自のレシピをld使用しています。binutils

私の実際の質問は次のとおりです。

これらのバージョンのコンパイラの違いは何ですか?gccまた、より大きなセクションを生成したり、elf オブジェクト ファイルを介してリンカにこれらのバイトをbootloader.binファイルの先頭に追加するように指示したりしますか?

gcc4.5よりも大きなセクションを生成する可能性がある機能をオフにしgccたり、ファイルの先頭にこれらのバイトを追加するようリンカーに指示する指示を削除したりする、 4.6 および/または 4.7のコマンド ライン引数はありbootloader.binますか?

edit 17-08-2012: 私は最近少し忙しいですが、すぐに私が行ったテストの結果を更新します.

bootloader.bin@strnkと@Dan Aloni への回答: この問題を見たとき、最初に行ったのは、役に立たないセクションを除外することでしたが、結果は同じです。セクション名、再配置、デバッグ情報、およびシンボルなしで、リンカが指示したとおりの正しい位置...bootloader.binファイルはelfオブジェクトファイルではありません。

実際の質問の変更を検討してください。いつもありがとう...すぐに戻ってきます

2012 年 8 月 31 日編集: わかりました皆さん、ご協力ありがとうございます。@Dan Aloni によって与えられ、@ ldscriptstrnk が示すように達成された答え

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

アサートの後。

4

4 に答える 4

8

gcc-4.5と の間で提供されたフラグを使用して簡単な C ファイルをコンパイルし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コード サイズが大きくなる可能性がある最適化を明示的に有効にします。ブートローダーは一度だけ実行されるため、 forを使用-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

次にld、オブジェクト ファイルをバイナリにリンクするために使用します。これldも binutils パッケージの一部です。

GCC をフロントエンドとして使用すると、問題が混乱し、メリットがほとんどまたはまったくなく、実際には問題の根底にある可能性があります。念のため、使用した GCC のバージョンは教えてくれましたが、使用したbinutilsのバージョンは教えてくれませんでした...

ビルド プロセスをできるだけシンプルに保つために、厳密には必要ないツールに依存しないことをお勧めします。この場合、ブートローダーのビルド ステップから GCC を削除します。

于 2012-08-16T10:15:38.030 に答える