我正在尝试将 xv6 引导代码从 At&t 语法转换为 Intel 语法,但我遇到了 ljmp 指令问题。我正在尝试学习 Intel 计算机的启动过程,但我对 Intel 汇编并不是特别擅长。
原始的 AT&T 语法是 ljmp $0x8, $start32
。
最小的例子:
.code16
jmp 0x8:start32 # won't assemble
.code32
start32:
nop
在 GNU Binutils 2.35.1 中使用 as -32 -msyntax=intel -mnaked-reg foo.s
生成
错误:junk ':start32' after expression
for the far jmp line.
我正在使用 GNU as 和 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
最佳答案
在您提供的完整翻译代码中,这一行是不正确的:
ljmp start32, 0x8
GNU 汇编程序的英特尔语法中 FAR JMP 的正确语法是:
ljmp 0x08, start32
首先是选择器值,其次是偏移量。似乎在从 AT&T 语法翻译时,您颠倒了这 2 个值,而顺序应该保持不变。如果值反转,您将得到错误 Error: can't handle non absolute segment in 'ljmp'
。在 GNU 汇编程序的 Intel 语法中,您还可以将 ljmp
替换为 jmp
,这样 jmp 0x08, start32
也可以工作。
有不同风格的英特尔语法。 jmp 0x8:start32
是 NASM 的 Intel 语法,它不同于 GNU Assembler 的 Intel 语法,其中 :
和 ,
不同。如果您使用 :
来分隔这两个值,您将在 GNU 汇编程序中收到错误 Error: junk ':start32' after expression
。
注意事项
- 如果
bootmain
中的代码不起作用,则可能是与您在本问题中提供的引导加载程序代码无关的问题。如果您还使用 Intel 语法而不是 AT&T 语法构建所有 C 代码,请确保所有内联汇编都已正确转换,因为源和操作数也会被反转。 xv6 可能在许多文件中都有内联汇编,包括xv6-public/x86.h
、xv6-public/spinlock.c
、xv6-public/usertests。 c
和xv6-public/stressfs.c
关于assembly - 来自 AT&T 语法的 Intel Assembly ljmp 语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65347376/