AT&T構文からのIntelアセンブリljmp構文

Dec 18 2020

xv6ブートコードをAt&t構文からIntel構文に変換しようとしていますが、ljmp命令に問題があります。私はIntelコンピュータの起動プロセスを学ぼうとしていますが、Intelアセンブリには特に力がありません。

元のAT&T構文はです。ljmp $0x8, $start32

最小限の例:

.code16
   jmp 0x8:start32          # won't assemble

.code32
start32:
   nop

as -32 -msyntax=intel -mnaked-reg foo.sGNU Binutils 2.35.1で使用する
Error: junk ':start32' after expressionと、farjmp行が生成されます。

私はGNUasとgccツールを使用しています。
gdtdescやgdtなど、アセンブリに他の問題がある可能性もあります。

Intel構文に移植された完全なコードは次のとおりです。

# Start the first CPU: switch to 32-bit protectied mode, jump into C.
# The BIOS loads this code from the first sector of the hard disk into
# memory at physical address 0x7c00 and starts executing in real mode
# with cs = 0 and ip = 7c00.
.code16
.global start
start:
    # Disable interrupts.
    cli

    # Zero data segment registers DS, ES, and SS.
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax

seta20.1:
    # Wait for not busy.
    in al, 0x64
    test al, 0x2
    jnz seta20.1

    # 0xd1 -> port 0x64
    mov al, 0xd1
    out 0x64, al

seta20.2:
    # Wait for not busy.
    in al, 0x64
    test al, 0x2
    jnz seta20.2

    # 0xdf -> port 0x60
    mov al, 0xdf
    out 0x60, al

    # Switch from real to protected mode. Use a bootstrap GDT that makes
    # virtual addresses map directly to physical addressses so that the
    # effective memory map doesn't change during the transition.
    lgdt gdtdesc

    # Protection Enable in cr0 register.
    mov eax, cr0
    or eax, 0x1
    mov cr0, eax

    # Complete the transtion to 32-bit protected mode by using a long jmp
    # to reload cs and eip. The segment descriptors are set up with no
    # translation, so that the mapping is still the identity mapping.

    # This instruction giving me problems.
    ljmp start32, 0x8

.code32
start32:
    # Set up the protected-mode data segment registers
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov ss, ax

    # Zero the segments not ready for use.
    xor ax, ax
    mov fs, ax
    mov gs, ax

    # Set up the stack pointer and call into C.
    mov esp, start
    call bootmain

    # If bootmain returns spin.. ??
spin:
    hlt
    jmp spin

# Bootstrap GDT set up null segment, code segment, and data segment respectively.
# Force 4 byte alignment.
.p2align 2
gdt:
    .word 0x0000, 0x0000
    .byte 0, 0, 0, 0
    .word 0xffff, 0x0000
    .byte 0, 0x9a, 0xcf, 0
    .word 0xffff, 0x0000
    .byte 0, 0x92, 0xcf, 0

# sizeof(gdt) - 1 and address of gdt respectively.
gdtdesc:
    .word (gdtdesc - gdt - 1)
    .long gdt

回答

3 PeterCordes Dec 18 2020 at 11:58

あなたが使用することができます jmp 0x08, start32

何らかの理由で、同等であるはずのコマンドライン引数を使用しjmp 0x8:start32.intel_syntax noprefix場合でも、の後にのみ機能します。これはBinutilsobjdump -d -Mintel -mi8086で使用される構文です。たとえばea 16 00 08 00 jmp 0x8:0x16、GASのバグであり、受け入れられない場合があります。


私はあなたの質問を編集してas、Jesterに返信するあなたのコメントに基づいて、2.35.1(Arch GNU / Linuxにあります)で小さな再現可能な例を作成しました。コマンドラインオプションを含め.intel_syntax noprefixました。ファイルにディレクティブがないため、これらを使用していたに違いないと思います。

それが問題のようです:-msyntax=intel -mnaked-regのような、他のインテルの構文物事が仕事になりxor ax,axますが、ないではない作るjmp 0x8:start32仕事(またはそれを書くの他の方法を)。.intel_syntax noprefix1つのディレクティブだけがfarjmpのその構文を機能させます。

# .intel_syntax noprefix        # rely on command line options to set this
.code16
   xor  ax, ax              # verify that command-line setting of intel_syntax worked, otherwise this line errors.

   ljmp 0x8, start32        # Working before or after a syntax directive, but is basically AT&T syntax
#   jmp 0x8:start32          # fails here, works after a directive
   jmp 0x8, start32         # Michael Petch's suggested syntax that's still somewhat AT&Tish.  works with just cmdline opts. 

.att_syntax
   ljmp $0x8, $start32      # working everywhere, even with clang
.intel_syntax noprefix
   jmp 0x8:start32          # objdump disassembly syntax, but only works after a .intel_syntax noprefix directive

.code32
start32:
   nop

-msyntax=intel -mnaked-regは、それらの効果が必要な他の指示のために働くことを確認しました:movzx ax, al働く。しかし-mnaked-reg、「ax」と「al」がシンボル名として使用されるため、「メモリ参照が多すぎます」というメッセージが表示されます。なしまたは「オペランドサイズの不一致」なし-msyntax=intel

リストGASからas -32 -msyntax=intel -mmnemonic=intel -mnaked-reg -o foo.o foo.s -al --listing-lhs-width=2 --listing-rhs-width=140
(私はかなり確信しているが-mmnemonic=intel無関係であり、構文=インテルによって暗示します。)

マシンコードがあるために機能した命令jmp 0x8:start32と、左側の列が空であるために機能しなかった(最初の)命令を確認できることに注意してください。通常、最初の列はアドレスですが、???? 組み立てに失敗したため。(jmp 0x8:start32最初は失敗したことを示すためにコメントを外したため、2回目は動作します。)

foo.s: Assembler messages:
foo.s:6: Error: junk `:start32' after expression
GAS LISTING foo.s                       page 1


   1                            # .intel_syntax noprefix        # rely on command line options to set this
   2                            .code16
   3 ???? 0FB6C0                   movzx   ax, al              # verify that command-line setting of intel_syntax worked, otherwise this line errors.
   4                       
   5 ???? EA170008 00              ljmp 0x8, start32        # Working before or after a syntax directive, but is basically AT&T syntax
   6                               jmp 0x8:start32          # fails here, works after a directive
   7 ???? EA170008 00              jmp 0x8, start32         # Michael Petch's suggested syntax that's still somewhat AT&Tish.  works with just cmdline opts. 
   8                       
   9                            .att_syntax
  10 ???? EA170008 00              ljmp $0x8, $start32      # working everywhere, even with clang
  11                            .intel_syntax noprefix
  12 ???? EA170008 00              jmp 0x8:start32          # objdump disassembly syntax, but only works after a .intel_syntax noprefix directive
  13                       
  14                            .code32
  15                            start32:
  16 ???? 90                       nop
  17                       

(GASは、左側の列のフィールド幅を「ワード」でリストします。これは、明らかに32ビットチャンクを意味します。そのため00、セグメントセレクターの最上位バイトはスペースで区切られます。)

にラベルを付けるjmp 0x8:labelことは役に立ちませんでした。前方参照と後方参照の問題ではありません。jmp 0x8:23組み立てに失敗することさえあります。


動作中のビルドからの逆アセンブラによる「推奨」構文:

objdump -drwC -Mintel -mi8086 foo.o

foo.o:     file format elf32-i386

Disassembly of section .text:

00000000 <start32-0x17>:
   0:   0f b6 c0                movzx  ax,al
   3:   ea 17 00 08 00          jmp    0x8:0x17 4: R_386_16     .text
   8:   ea 17 00 08 00          jmp    0x8:0x17 9: R_386_16     .text
   d:   ea 17 00 08 00          jmp    0x8:0x17 e: R_386_16     .text
  12:   ea 17 00 08 00          jmp    0x8:0x17 13: R_386_16    .text

00000017 <start32>:
  17:   90                      nop

llvm-objdump --mattr=+16bit-mode --x86-asm-syntax=intel -d foo.o

00000000 <.text>:
       0: 0f b6 c0                      movzx   ax, al
       3: ea 17 00 08 00                ljmp    8, 23
       8: ea 17 00 08 00                ljmp    8, 23
       d: ea 17 00 08 00                ljmp    8, 23
      12: ea 17 00 08 00                ljmp    8, 23

00000017 <start32>:
      17: 90                            nop

ところで、シンボル名を使用してこれのIntel構文バージョンをアセンブルするためのclang11.0を入手できませんでした。ljmp 8, 12clangでアセンブルしますが、ljmp 8, start32。AT&T構文に切り替えて元に戻すだけで、clangの組み込みアセンブラー(clang -m32 -masm=intel -c)で16ビットモードのfarjmpを出力できます。

.att_syntax
   ljmp $0x8, $start32      # working everywhere, even with clang
.intel_syntax noprefix

この直接形式のfarJMPは、64ビットモードでは使用できないことに注意してください。おそらくそれが、LLVMの組み込みアセンブラーがそれに費やした労力が少ないように見える理由です。


脚注1:実際にも.intel_syntax prefix機能しますが、決して使用しないでください。誰もmov %eax, [%eax]、または特に注文add %edx, %eaxを使用しているdst, srcが、AT&Tで装飾されたレジスタ名を持つフランケンモンスターを見たくありません。

3 MichaelPetch Dec 18 2020 at 10:55

あなたが提示した完全に翻訳されたコードでは、この行は正しくありません:

ljmp start32, 0x8

GNUアセンブラのIntel構文におけるFARJMPの適切な構文は次のとおりです。

ljmp 0x08, start32

セレクター値が最初になり、オフセットが2番目になります。AT&T構文からの翻訳では、順序が同じであるはずのときにこれら2つの値を逆にしたようです。値を逆にすると、エラーが発生しますError: can't handle non absolute segment in 'ljmp'。GNUアセンブラでのインテルはあなたにも代用できる構文ljmpjmpそうjmp 0x08, start32同様に動作します。

Intel構文にはさまざまな種類があります。jmp 0x8:start32はNASMのIntel構文であり、とが異なるGNUアセンブラのIntel構文:とは,異なります。を使用し:て2つの値を区切ると、Error: junk ':start32' after expressionGNUアセンブラでエラーが発生します。


ノート

  • のコードがbootmain機能しない場合は、この質問で提示したブートローダーコードとは関係のない問題である可能性があります。AT&T構文ではなくIntel構文を使用してすべてのCコードも構築している場合は、すべてのインラインアセンブリがソースとして適切に変換され、オペランドも逆になっていることを確認してください。xv6可能性が高いなどのファイルの数にインラインアセンブリありxv6-public/x86.hxv6-public/spinlock.cxv6-public/usertests.cおよびxv6-public/stressfs.c