AT & T 구문의 인텔 어셈블리 ljmp 구문
xv6 부트 코드를 At & t 구문에서 Intel 구문으로 변환하려고하는데 ljmp 명령에 문제가 있습니다. 저는 Intel 컴퓨터의 부팅 과정을 배우려고하는데 Intel 어셈블리에 특별히 강하지 않습니다.
원래 AT & T 구문은 .ljmp $0x8, $start32
최소한의 예 :
.code16
jmp 0x8:start32 # won't assemble
.code32
start32:
nop
as -32 -msyntax=intel -mnaked-reg foo.s
GNU Binutils 2.35.1과 함께 사용
Error: junk ':start32' after expression
하면 먼 jmp 라인이 생성 됩니다.
나는 GNU와 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
답변
당신이 사용할 수있는 jmp 0x08, start32
어떤 이유로, 동등해야하는 명령 줄 인수가 있더라도 jmp 0x8:start32
이후에만 작동 .intel_syntax noprefix
합니다. 이것은 Binutils objdump -d -Mintel -mi8086
에서 사용하는 구문입니다 . 예를 들어 ea 16 00 08 00 jmp 0x8:0x16
때때로 허용되지 않는 GAS 버그 일 수 있습니다.
as
Jester에 대한 귀하의 의견을 기반으로 2.35.1 (Arch GNU / Linux에 있음)으로 재현 가능한 작은 예제를 만들기 위해 귀하의 질문을 편집했습니다 . 명령 줄 옵션을 포함했습니다 .intel_syntax noprefix
. 파일에 지시문 이 없기 때문에이 옵션을 사용 했어야한다고 가정 합니다.
이것이 문제인 것 같습니다. -msyntax=intel -mnaked-reg
다른 인텔 구문을, 같은 작동 하게 xor ax,ax
하지만 작동하지는 않습니다jmp 0x8:start32
(또는 다른 작성 방법). 단 .intel_syntax noprefix
1 지시문 만이 far jmp에 대한 구문을 작동시킵니다.
# .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
-msyntax=intel -mnaked-reg
효과가 필요한 다른 지침에 대한 작업 인 작동 함을 확인했습니다 movzx ax, al
. 그러나 -mnaked-reg
"ax"와 "al"이 기호 이름으로 사용되기 때문에 "너무 많은 메모리 참조"를 얻게됩니다. 없이 또는 "피연산자 크기 불일치"없이 -msyntax=intel
.
목록 가스 에서 as -32 -msyntax=intel -mmnemonic=intel -mnaked-reg -o foo.o foo.s -al --listing-lhs-width=2 --listing-rhs-width=140
(나는 확신는 -mmnemonic=intel
무관하고, 구문 = 인텔 암시입니다.)
기계 코드가 있기 때문에 어떤 명령어가 작동했는지 jmp 0x8:start32
, 왼쪽 열이 비어 있기 때문에 작동 하지 않은 명령어 (첫 번째 )를 확인할 수 있습니다. 첫 번째 열은 일반적으로 주소이지만 ???? 조립이 실패했기 때문입니다. ( jmp 0x8:start32
첫 번째 실패를 보여주기 위해 주석을 제거했기 때문에 두 번째 작업을 수행했습니다.)
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는 "단어"의 왼쪽 열에 대한 필드 너비를 나열합니다. 이는 분명히 32 비트 청크를 의미합니다. 이것이 00
세그먼트 선택기 의 가장 중요한 바이트가 공백으로 구분되는 이유 입니다.)
라벨을 넣기 전에 (가) jmp 0x8:label
도움이되지 않았다; 순방향 참조와 역방향 참조의 문제가 아닙니다. jmp 0x8:23
조립 에도 실패합니다.
작업 빌드에서 디스어셈블러에 의해 "권장되는"구문 :
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
그리고 BTW, 나는 기호 이름으로 이것의 Intel 구문 버전을 어셈블하기 위해 clang 11.0을 얻지 못했습니다. ljmp 8, 12
clang으로 어셈블되지만 ljmp 8, start32
. AT & T 구문으로 전환 한 후에 만 clang의 기본 제공 어셈블러 ( clang -m32 -masm=intel -c
)를 사용하여 16 비트 모드 far jmp를 내보낼 수 있습니다.
.att_syntax
ljmp $0x8, $start32 # working everywhere, even with clang
.intel_syntax noprefix
이 직접적인 형태의 원거리 JMP는 64 비트 모드에서 사용할 수 없습니다. 아마도 이것이 LLVM의 내장 어셈블러가 더 적은 노력을 기울이는 이유입니다.
각주 1 : 실제로 .intel_syntax prefix
작동하지만 절대 사용하지 마십시오. 누구도 franken-monster mov %eax, [%eax]
, 또는 특히 주문을 add %edx, %eax
사용 dst, src
하지만 AT & T 장식 레지스터 이름 을보고 싶어하지 않습니다 .
귀하가 제시 한 전체 번역 코드에서이 행은 올바르지 않습니다.
ljmp start32, 0x8
GNU Assembler의 Intel 구문에서 FAR JMP에 대한 적절한 구문은 다음과 같습니다.
ljmp 0x08, start32
선택기 값은 첫 번째이고 오프셋은 두 번째입니다. AT & T 구문에서 번역 할 때 순서가 동일해야 할 때이 두 값을 뒤집은 것 같습니다. 값이 반전되면 오류가 발생했을 것 Error: can't handle non absolute segment in 'ljmp'
입니다. GNU 어셈블러의 인텔은 또한 대체 할 수있는 구문 ljmp
과 jmp
매우 jmp 0x08, start32
잘 작동.
Intel 구문에는 다양한 종류가 있습니다. jmp 0x8:start32
NASM의 Intel 구문이며과가 다른 GNU Assembler의 Intel 구문 :
과 ,
다릅니다. a를 사용 :
하여 두 값을 분리하면 Error: junk ':start32' after expression
GNU Assembler 에서 오류가 발생 합니다.
메모
- 코드
bootmain
가 작동하지 않으면이 질문에서 제시 한 부트 로더 코드와 관련이없는 문제 일 수 있습니다. AT & T 구문이 아닌 Intel 구문을 사용하여 모든 C 코드를 빌드하는 경우 모든 인라인 어셈블리가 소스로 올바르게 변환되었는지 확인하고 피연산자도 반전되었는지 확인합니다. xv6 가능성을 포함하여 파일의 숫자에 인라인 어셈블리가xv6-public/x86.h
,xv6-public/spinlock.c
,xv6-public/usertests.c
및xv6-public/stressfs.c