Intel Assembly ljmp-Syntax aus der AT & T-Syntax
Ich versuche, den xv6-Startcode von der At & t-Syntax in die Intel-Syntax zu konvertieren, und ich habe ein Problem mit der ljmp-Anweisung. Ich versuche, den Startvorgang von Intel-Computern zu erlernen, und ich bin nicht besonders stark in der Intel-Montage.
Die ursprüngliche AT & T-Syntax lautet .ljmp $0x8, $start32
Minimales Beispiel:
.code16
jmp 0x8:start32 # won't assemble
.code32
start32:
nop
Die Verwendung as -32 -msyntax=intel -mnaked-reg foo.s
mit GNU Binutils 2.35.1 erzeugt
Error: junk ':start32' after expression
für die ferne jmp-Linie.
Ich benutze GNU als und gcc Tools.
Möglicherweise gibt es auch andere Probleme mit der Assembly, z. B. gdtdesc und gdt.
Der vollständige Code, der auf die Intel-Syntax portiert ist, lautet:
# 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
Antworten
Sie können verwenden jmp 0x08, start32
Funktioniert aus irgendeinem Grund jmp 0x8:start32
erst danach .intel_syntax noprefix
, auch mit Befehlszeilenargumenten, die gleichwertig sein sollten. Dies ist die von Binutils verwendete Syntax objdump -d -Mintel -mi8086
, z. B. handelt ea 16 00 08 00 jmp 0x8:0x16
es sich wahrscheinlich um einen GAS-Fehler, der manchmal nicht akzeptiert wird.
Ich habe Ihre Frage bearbeitet, um ein kleines reproduzierbares Beispiel mit as
2.35.1 (das ich unter Arch GNU / Linux habe) zu erstellen, basierend auf Ihren Kommentaren, die Jester antworten. Ich habe Befehlszeilenoptionen eingefügt: Ich gehe davon aus, dass Sie diese verwendet haben müssen, da .intel_syntax noprefix
Ihre Datei keine Direktive enthält.
Das scheint das Problem zu sein: -msyntax=intel -mnaked-reg
macht andere Intel - Syntax Dinge funktionieren, wie xor ax,ax
, aber nicht nicht machen jmp 0x8:start32
Arbeit (oder andere Art und Weise des Schreibens es). Nur eine .intel_syntax noprefix
1- Direktive bewirkt, dass diese Syntax für far jmp funktioniert.
# .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
Ich habe überprüft, dass die -msyntax=intel -mnaked-reg
Arbeit für andere Anweisungen funktioniert, bei denen ihre Wirkung erforderlich ist: movzx ax, al
funktioniert. Aber ohne würden -mnaked-reg
wir "zu viele Speicherreferenzen" erhalten, weil "ax" und "al" als Symbolnamen verwendet würden. Ohne oder "Nichtübereinstimmung der Operandengröße" ohne -msyntax=intel
.
Eine GAS-Auflistung von as -32 -msyntax=intel -mmnemonic=intel -mnaked-reg -o foo.o foo.s -al --listing-lhs-width=2 --listing-rhs-width=140
(Ich bin mir ziemlich sicher -mmnemonic=intel
, dass dies irrelevant ist und durch Syntax = Intel impliziert wird.)
Beachten Sie, dass Sie sehen können, welche Anweisungen funktionierten, weil sie Maschinencode haben, und welche nicht (die erste jmp 0x8:start32
), weil die linke Spalte dafür leer ist. Die allererste Spalte wäre normalerweise Adressen, ist aber ???? weil die Montage fehlgeschlagen ist. (Weil ich das nicht kommentiert habe, um jmp 0x8:start32
zu zeigen, dass es beim ersten Mal fehlschlägt und beim zweiten Mal funktioniert.)
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 listet die Feldbreiten für die linke Spalte in "Wörtern" auf, was anscheinend 32-Bit-Blöcke bedeutet. Deshalb wird das 00
höchstwertige Byte des Segmentselektors durch ein Leerzeichen getrennt.)
Ein Etikett vor das zu setzen jmp 0x8:label
half nicht; Es geht nicht um Vorwärts- oder Rückwärtsreferenz. Auch jmp 0x8:23
versagt nicht zusammenzubauen.
Von Disassemblern "empfohlene" Syntax aus einem funktionierenden Build:
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
Übrigens, ich habe kein Clang 11.0 bekommen, um Intel-Syntax-Versionen davon mit einem Symbolnamen zusammenzustellen. ljmp 8, 12
montiert mit Klirren, aber nicht einmal ljmp 8, start32
. Nur durch Umschalten auf AT & T-Syntax und zurück konnte ich Clangs eingebauten Assembler ( clang -m32 -masm=intel -c
) dazu bringen, einen 16-Bit-Modus für jmp auszugeben.
.att_syntax
ljmp $0x8, $start32 # working everywhere, even with clang
.intel_syntax noprefix
Beachten Sie, dass diese direkte Form von Fern-JMP im 64-Bit-Modus nicht verfügbar ist. Vielleicht hat der integrierte Assembler von LLVM deshalb weniger Aufwand betrieben.
Fußnote 1: Funktioniert eigentlich .intel_syntax prefix
auch, aber benutze das nie. Niemand möchte das Franken-Monster sehen, das ist mov %eax, [%eax]
, oder besonders das add %edx, %eax
, das dst, src
Ordnung verwendet, aber mit AT & T-dekorierten Registernamen.
In dem vollständig übersetzten Code, den Sie präsentiert haben, ist diese Zeile falsch:
ljmp start32, 0x8
Die richtige Syntax für ein FAR JMP in der Intel-Syntax von GNU Assembler lautet:
ljmp 0x08, start32
Der Auswahlwert wäre der erste und der Versatz der zweite. Es scheint, dass Sie bei der Übersetzung aus der AT & T-Syntax diese beiden Werte umgekehrt haben, wenn die Reihenfolge gleich geblieben sein sollte. Wenn die Werte umgekehrt wären, hätten Sie den Fehler erhalten Error: can't handle non absolute segment in 'ljmp'
. In GNU Assembler Intel Syntax Sie auch ersetzen können ljmp
mit jmp
so jmp 0x08, start32
auch funktionieren würde.
Es gibt verschiedene Varianten der Intel-Syntax. jmp 0x8:start32
ist die Intel-Syntax von NASM und unterscheidet sich von der Intel-Syntax von GNU Assembler, bei der sich die :
und ,
unterscheiden. Wenn Sie a verwenden :
, um die beiden Werte zu trennen, wird der Fehler Error: junk ':start32' after expression
in GNU Assembler angezeigt.
Anmerkungen
- Wenn der Code in
bootmain
nicht funktioniert, liegt wahrscheinlich ein Problem vor, das nicht mit dem Bootloader-Code zusammenhängt, den Sie in dieser Frage vorgestellt haben. Wenn Sie auch den gesamten C- Code mit Intel-Syntax anstelle der AT & T-Syntax erstellen, stellen Sie sicher, dass die gesamte Inline-Assembly ordnungsgemäß konvertiert wurde, da Quelle und Operand ebenfalls umgekehrt worden wären. xv6 wahrscheinlich hat Inline - Assembly in einer Reihe von Dateien , einschließlichxv6-public/x86.h
,xv6-public/spinlock.c
,xv6-public/usertests.c
undxv6-public/stressfs.c