0

さて、アセンブリ/C で 2 段階のブートローダーを作成しようとしましたが、JMP を機能させることができませんでした。最初は読み取りが失敗していると思いましたが、次のテストの後、それを除外しました。

__asm__ __volatile__(
    "xorw %ax, %ax;"
    "movw %ax, %ds;"
    "movw %ax, %es;"
    "movb $0x02, %ah;"
    "movb $0x01, %al;"
    "movw $0x7E00, %bx;"
    "movw $0x0003, %cx;"
    "xorb %dh, %dh;"
    "int $0x13;"
    "movb 0x7E00, %al;"
    "movb $0x0e, %ah;"
    "int $0x10;"
    //"jmp 0x7E00"
);

これにより、期待どおりに「f」が出力され(セクターの最初のバイトは「f」のASCIIコードである0x66です)、読み取りが成功し、これjmpが問題であることを証明しています。これは私のコードです:

__asm__(".code16\n");
__asm__(".code16gcc\n");
__asm__("jmpl $0x0000, $main\n");
void main(){
    __asm__ __volatile__(
        "xorw %ax, %ax;"
        "movw %ax, %ds;"
        "movw %ax, %es;"
        "movb $0x02, %ah;"
        "movb $0x01, %al;"
        "movw $0x7E00, %bx;"
        "movw $0x0003, %cx;"
        "xorb %dh, %dh;"
        "int $0x13;"
        "jmp $0x200;"
    );
}

実行すると、プログラムが単にハングします。これは、プログラムがメモリ内の間違った場所にジャンプしている可能性があることを意味します。ところで、私は明らかにこれを VMWare プレーヤーの下でリアル モードで実行しています。これを次のコマンドでコンパイルしています。

gcc -c -0s -march=i686 -ffreestanding -Wall -Werror boot.c -o boot.o
ld -static -Ttest.ld -nostdlib --nmagic -o boot.elf boot.o --no-check-sections
objcopy -0 binary boot.elf boot.bin

これはtest.ld次のとおりです。

ENTRY(main);
SECTIONS
{
    . = 0x7C00;
    .text : AT(0x7C00)
    {
        *(.test);
    }
    .sig : AT(0x7DFE)
    {
        SHORT(0xAA55);
    }
}

注: これはインライン asm の問題ではないことを確認しました - 純粋なアセンブリの実装も試してみましたが、同じ結果が得られました - C を使用している唯一の理由は、これを少し拡張する予定であり、はるかに快適だからです。 Cループと関数で...

編集:フロッピー ドライブの最初の 3 セクタをここにアップロードしました

編集 2:提案を使用してブートローダーを動作させることができませんでした。@RossRidge からのアドバイスに基づいて、同じプログラムのアセンブリ バージョンと、入力をエコーする単純なアセンブリ プログラムを作成しました。悲しいことに、これらも機能していません..

ブートローダー:

org 0x7c00
xor ax, ax
mov ds, ax
mov es, ax
mov ah, 0x02
mov al, 0x01
mov bx, 0x7E00
mov cx, 0x0003
xor dh, dh
int 0x13
jmp 0x7E00

セクター 3 のプログラム:

xor ax, ax
int 0x16
mov ah, 0xe
int 0x10

これらはどちらも次のようにコンパイルされてnasm Linux/boot.S -o Linux/asm.binおり、対応する C と同じように動作します。

4

2 に答える 2

3

アセンブラが間違ったジャンプ オフセットを生成していることは確かです。現在のテキスト セクションで相対的に解釈されている可能性がありますが、リンカー スクリプトによって0x7e00マップされているため、ジャンプはおそらく代わりに行われます。醜い回避策として、代わりに試すか、間接的なジャンプを使用して などのツールから非表示にすることができます。あるいは、機能することもあります。0x7c000x7c00+0x7e00=0xfa00jmp 0x200mov $0x7e00, %ax; jmp *%axjmp .text+0x200

また、32 ビット C コンパイラで 16 ビット asm を書き込むと間違ったコードが生成されることに注意してください。これは、ロードされたセクターの最初のバイトがオペランド サイズ オーバーライド プレフィックスである 0x66 であることからも示唆されます。コンパイラは 32 ビット モードを想定しているため、16 ビット モードで実行すると 32 ビットに戻るプレフィックス付きの 16 ビット コードが生成されます。一般に、このような目的でインライン asm を悪用することはお勧めできません。別の asm ファイルを使用し、コードが 16 ビット リアル モード用であることをアセンブラに伝える必要があります。

PS: デバッガーの使い方を学びましょう。


更新: を使用して組み立てた場合の次のコードは、および でnasm boot.asm -o boot.bin正常に動作します:qemubochs

org 0x7c00
xor ax, ax
mov ds, ax
mov es, ax
mov ah, 0x02
mov al, 0x01
mov bx, 0x7E00
mov cx, 0x0003
xor dh, dh
int 0x13
jmp 0x7E00

times 510-($-$$) db 0
dw 0xaa55
; second sector
times 512 db 0
; Program in sector 3:
xor ax, ax
int 0x16
mov ah, 0xe
int 0x10
jmp $
times 1536-($-$$) db 0

ここから画像をダウンロードできます(限定オファー ;))。

于 2015-05-23T21:23:05.677 に答える
0

私は多くのブートローダーを書いてきました。

2 つの別個の実行可能ファイルが必要です。

1) the boot loader
2) the main code

そのため、ロードされたコード (メイン プログラム) は、ブート ローダーに何もせずに更新できます。

ブートローダーは、完了したら既知の場所にジャンプする必要があります。

メイン プログラムは、librt ライブラリ内の関数にジャンプするジャンプ命令を既知の場所に配置する必要があります。(通常はstart())

start() は I/O、ヒープなどを設定し、main() を呼び出します

ブートローダのリンカ コマンド ファイルとメイン プログラムのリンカ コマンド ファイルの両方が、既知の場所のアドレスに同意する必要があります。

通常、既知の場所は、両方のリンカー コマンド ファイルの固有のセクションにある唯一のものです。

ブートローダーは、メインプログラムのすべての部分をメモリ内の適切な領域に配置できるほどスマートでなければなりません。

メイン プログラムは生の .elf または .coff 形式ではなく、motorola S1 (または同様の) 形式であることが最適です。そうしないと、ブートローダーが非常に急速に大きくなる可能性があります。

于 2015-05-24T22:31:35.390 に答える