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.smit GNU Binutils 2.35.1 erzeugt
Error: junk ':start32' after expressionfü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:start32erst 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:0x16es sich wahrscheinlich um einen GAS-Fehler, der manchmal nicht akzeptiert wird.
Ich habe Ihre Frage bearbeitet, um ein kleines reproduzierbares Beispiel mit as2.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 noprefixIhre Datei keine Direktive enthält.
Das scheint das Problem zu sein: -msyntax=intel -mnaked-regmacht andere Intel - Syntax Dinge funktionieren, wie xor ax,ax, aber nicht nicht machen jmp 0x8:start32Arbeit (oder andere Art und Weise des Schreibens es). Nur eine .intel_syntax noprefix1- 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-regArbeit für andere Anweisungen funktioniert, bei denen ihre Wirkung erforderlich ist: movzx ax, alfunktioniert. Aber ohne würden -mnaked-regwir "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:start32zu 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 00höchstwertige Byte des Segmentselektors durch ein Leerzeichen getrennt.)
Ein Etikett vor das zu setzen jmp 0x8:labelhalf nicht; Es geht nicht um Vorwärts- oder Rückwärtsreferenz. Auch jmp 0x8:23versagt 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, 12montiert 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 prefixauch, aber benutze das nie. Niemand möchte das Franken-Monster sehen, das ist mov %eax, [%eax], oder besonders das add %edx, %eax, das dst, srcOrdnung 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 ljmpmit jmpso jmp 0x08, start32auch funktionieren würde.
Es gibt verschiedene Varianten der Intel-Syntax. jmp 0x8:start32ist 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 expressionin GNU Assembler angezeigt.
Anmerkungen
- Wenn der Code in
bootmainnicht 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.cundxv6-public/stressfs.c