Sintaks ljmp Majelis Intel dari sintaks AT&T
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.s
dengan GNU Binutils 2.35.1 menghasilkan
Error: junk ':start32' after expression
baris 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
Kamu bisa memakai jmp 0x08, start32
Untuk beberapa alasan, jmp 0x8:start32
hanya 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:0x16
jadi mungkin ada bug GAS yang terkadang tidak diterima.
Saya mengedit pertanyaan Anda untuk membuat contoh kecil yang dapat direproduksi dengan as
2.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 noprefix
arahan di file Anda.
Tampaknya itulah masalahnya: -msyntax=intel -mnaked-reg
membuat sintaks Intel lainnya berfungsi, seperti xor ax,ax
, tetapi tidak membuat jmp 0x8:start32
berfungsi (atau cara lain untuk menulisnya). Hanya .intel_syntax noprefix
1 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-reg
berfungsi untuk instruksi lain di mana efeknya diperlukan: movzx ax, al
berfungsi. Tapi tanpa -mnaked-reg
kita 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=intel
tidak 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:start32
untuk 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 00
byte paling signifikan dari pemilih segmen dipisahkan oleh spasi.)
Menempatkan label sebelum itu jmp 0x8:label
tidak membantu; ini bukan masalah referensi maju vs mundur. Bahkan jmp 0x8:23
gagal 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, 12
berkumpul 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 prefix
berfungsi juga, tetapi tidak pernah menggunakannya. Tak seorang pun ingin melihat monster-franken itu mov %eax, [%eax]
, atau terutama add %edx, %eax
yang menggunakan dst, src
pesanan, tetapi dengan nama register yang didekorasi dengan AT&T.
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 ljmp
dengan jmp
itu jmp 0x08, start32
akan bekerja juga.
Ada berbagai rasa sintaks Intel. jmp 0x8:start32
adalah 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 expression
di GNU Assembler.
Catatan
- Jika kode
bootmain
tidak 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 termasukxv6-public/x86.h
,xv6-public/spinlock.c
,xv6-public/usertests.c
danxv6-public/stressfs.c