Sintaks ljmp Majelis Intel dari sintaks AT&T

Dec 18 2020

Saya mencoba untuk mengubah kode boot xv6 dari sintaks At & t ke sintaks Intel dan saya punya masalah dengan instruksi ljmp. Saya mencoba mempelajari proses boot komputer Intel dan saya tidak terlalu kuat dengan perakitan Intel.

Sintaks asli AT&T adalah .ljmp $0x8, $start32

Contoh minimal:

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

.code32
start32:
   nop

Menggunakan as -32 -msyntax=intel -mnaked-reg foo.sdengan GNU Binutils 2.35.1 menghasilkan
Error: junk ':start32' after expressionbaris jmp jauh.

Saya menggunakan GNU sebagai, dan alat gcc.
Mungkin juga ada masalah lain dengan perakitan seperti gdtdesc dan gdt.

Kode lengkap yang diporting ke sintaks Intel adalah:

# 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

Jawaban

3 PeterCordes Dec 18 2020 at 11:58

Kamu bisa memakai jmp 0x08, start32

Untuk beberapa alasan, jmp 0x8:start32hanya berfungsi setelahnya .intel_syntax noprefix, bahkan dengan argumen baris perintah yang seharusnya setara. Ini adalah sintaks yang digunakan oleh Binutils objdump -d -Mintel -mi8086, misalnya ea 16 00 08 00 jmp 0x8:0x16jadi mungkin ada bug GAS yang terkadang tidak diterima.


Saya mengedit pertanyaan Anda untuk membuat contoh kecil yang dapat direproduksi dengan as2.35.1 (yang saya miliki di Arch GNU / Linux) berdasarkan komentar Anda yang membalas Jester. Saya menyertakan opsi baris perintah: Saya berasumsi Anda pasti telah menggunakan itu karena tidak ada .intel_syntax noprefixarahan di file Anda.

Tampaknya itulah masalahnya: -msyntax=intel -mnaked-regmembuat sintaks Intel lainnya berfungsi, seperti xor ax,ax, tetapi tidak membuat jmp 0x8:start32berfungsi (atau cara lain untuk menulisnya). Hanya .intel_syntax noprefix1 direktif yang membuat sintaks untuk far jmp berfungsi.

# .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

Saya memverifikasi bahwa -msyntax=intel -mnaked-regberfungsi untuk instruksi lain di mana efeknya diperlukan: movzx ax, alberfungsi. Tapi tanpa -mnaked-regkita akan mendapatkan "terlalu banyak referensi memori" karena "ax" dan "al" akan diambil sebagai nama simbol. Tanpa atau "ketidakcocokan ukuran operan" tanpa -msyntax=intel.

Daftar GAS dari as -32 -msyntax=intel -mmnemonic=intel -mnaked-reg -o foo.o foo.s -al --listing-lhs-width=2 --listing-rhs-width=140
(Saya cukup yakin -mmnemonic=inteltidak relevan, dan tersirat oleh sintaks = intel.)

Perhatikan bahwa Anda dapat melihat instruksi mana yang berfungsi karena mereka memiliki kode mesin, dan mana yang tidak (yang pertama jmp 0x8:start32) karena kolom sebelah kiri kosong untuk itu. Kolom pertama biasanya adalah alamat, tetapi ???? karena perakitan gagal. (Karena saya menghapus komentar jmp 0x8:start32untuk menunjukkannya gagal pertama kali, bekerja untuk kedua kalinya.)

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 mencantumkan lebar bidang untuk kolom kiri dalam "kata", yang tampaknya berarti potongan 32-bit. Itulah mengapa 00byte paling signifikan dari pemilih segmen dipisahkan oleh spasi.)

Menempatkan label sebelum itu jmp 0x8:labeltidak membantu; ini bukan masalah referensi maju vs mundur. Bahkan jmp 0x8:23gagal merakit.


Sintaks "direkomendasikan" oleh disassembler, dari build yang berfungsi:

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

Dan BTW, saya tidak mendapatkan dentang 11.0 untuk merakit versi sintaks Intel apa pun dari ini dengan nama simbol. ljmp 8, 12berkumpul dengan dentang, tapi tidak genap ljmp 8, start32. Hanya dengan beralih ke sintaks AT&T dan kembali, saya bisa mendapatkan assembler built-in clang ( clang -m32 -masm=intel -c) untuk memancarkan mode 16-bit jmp jauh.

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

Ingatlah bahwa bentuk JMP jauh ini tidak tersedia dalam mode 64-bit; mungkin itu sebabnya assembler built-in LLVM tampaknya telah menghabiskan lebih sedikit usaha untuk itu.


Catatan kaki 1: Sebenarnya .intel_syntax prefixberfungsi juga, tetapi tidak pernah menggunakannya. Tak seorang pun ingin melihat monster-franken itu mov %eax, [%eax], atau terutama add %edx, %eaxyang menggunakan dst, srcpesanan, tetapi dengan nama register yang didekorasi dengan AT&T.

3 MichaelPetch Dec 18 2020 at 10:55

Dalam kode terjemahan lengkap yang Anda berikan, baris ini salah:

ljmp start32, 0x8

Sintaks yang tepat untuk FAR JMP di sintaks Intel GNU Assembler adalah:

ljmp 0x08, start32

Nilai selektor akan menjadi yang pertama dan offset yang kedua. Tampaknya dalam menerjemahkan dari sintaks AT&T Anda membalikkan 2 nilai ini ketika urutannya seharusnya tetap sama. Dengan nilai dibalik, Anda akan mendapatkan kesalahan Error: can't handle non absolute segment in 'ljmp'. Dalam sintaks Intel GNU Assembler Anda juga dapat menggantinya ljmpdengan jmpitu jmp 0x08, start32akan bekerja juga.

Ada berbagai rasa sintaks Intel. jmp 0x8:start32adalah sintaks Intel NASM dan berbeda dari sintaks Intel GNU Assembler di mana :dan ,berbeda. Jika Anda menggunakan a :untuk memisahkan dua nilai, Anda akan mendapatkan kesalahan Error: junk ':start32' after expressiondi GNU Assembler.


Catatan

  • Jika kode bootmaintidak berfungsi, kemungkinan besar ada masalah yang tidak terkait dengan kode bootloader yang Anda berikan dalam pertanyaan ini. Jika Anda juga membuat semua kode C dengan Sintaks Intel daripada sintaks AT&T, pastikan semua rakitan inline telah diubah dengan benar karena sumber dan operan juga akan dibalik. xv6 mungkin memiliki inline perakitan di sejumlah file termasuk xv6-public/x86.h, xv6-public/spinlock.c, xv6-public/usertests.cdanxv6-public/stressfs.c