Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 来自AT&;的英特尔汇编ljmp语法;T语法_Assembly_X86 16_Gnu Assembler_Att_Intel Syntax - Fatal编程技术网

Assembly 来自AT&;的英特尔汇编ljmp语法;T语法

Assembly 来自AT&;的英特尔汇编ljmp语法;T语法,assembly,x86-16,gnu-assembler,att,intel-syntax,Assembly,X86 16,Gnu Assembler,Att,Intel Syntax,我正在尝试将xv6引导代码从At&t语法转换为Intel语法,但ljmp指令有问题。我正在努力学习英特尔计算机的引导过程,但我对英特尔汇编不是特别在行 原始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一起使

我正在尝试将xv6引导代码从At&t语法转换为Intel语法,但ljmp指令有问题。我正在努力学习英特尔计算机的引导过程,但我对英特尔汇编不是特别在行

原始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:far jmp行的表达式后的start32

我正在使用GNU as和gcc工具。
该程序集还可能存在其他问题,例如gdtdesc和gdt

移植到英特尔语法的完整代码如下:

# 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 0x08, start32

在您提供的完整翻译代码中,此行不正确:

ljmp start32, 0x8
GNU汇编程序英特尔语法中FAR JMP的正确语法为:

# 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 0x08, start32
选择器值为第一个,偏移量为第二个。从AT&T语法的翻译中,您似乎颠倒了这两个值,而顺序本应保持不变。如果将这些值反转,则会出现错误
error:cannothandlenon-absolutesegment in'ljmp'
。在GNU汇编程序的英特尔语法中,您还可以用
jmp
替换
ljmp
,这样
jmp 0x08,start32
也可以工作

英特尔语法有不同的风格
jmp 0x8:start32
是NASM的英特尔语法,它不同于GNU汇编程序的英特尔语法,后者的
不同。如果使用
来分隔这两个值,则会在GNU汇编程序中的表达式后得到错误
error:junk':start32'


笔记
  • 如果
    bootmain
    中的代码不起作用,则可能是与您在本问题中介绍的引导加载程序代码无关的问题。如果您还使用Intel语法而不是AT&T语法构建所有C代码,那么请确保所有内联程序集都已正确转换,因为源代码和操作数也将被反转。xv6可能在许多文件中都有内联程序集,包括
    xv6 public/x86.h
    xv6 public/spinlock.c
    xv6 public/usertests.c
    xv6 public/stressfs.c

    • 您可以使用
      jmp 0x08,start32

      由于某些原因,
      jmp 0x8:start32
      仅在
      之后才起作用。英特尔语法noprefix
      ,即使命令行参数应该是等效的。这是Binutils使用的语法
      objdump-d-Mintel-mi8086
      ,例如
      ea 16 00 08 00 jmp 0x8:0x16
      ,因此它可能是一个气体错误,有时不被接受


      根据您对Jester的回复,我编辑了您的问题,创建了一个小的可复制示例,使用
      as
      2.35.1(我在Arch GNU/Linux上有这个示例)。我包括了命令行选项:我假设您一定使用了这些选项,因为您的文件中没有
      .intel\u 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

      A GAS listfrom
      as-32-msyntax=intel-mmnemonic=intel-mnaked reg-o foo.o foo.s-al--list lhs width=2--list rhs width=140

      (我非常确定
      -mmnemonic=intel
      是不相关的,syntax=intel暗示了这一点。)

      注意,您可以看到哪些指令工作是因为它们有机器代码,而哪些指令没有工作(第一个
      jmp 0x8:start32
      ),因为左边的列为空。第一列通常是地址,但是是????因为程序集失败。(因为我取消了jmp 0x8:start32的注释,以显示它第一次失败,第二次工作。)

      (GAS没有在“words”中列出左列的字段宽度,这显然意味着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
      
      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
      
      顺便说一句,我没有让Clang11.0用符号名来组装任何英特尔语法版本
      LJMP8,12
      以铿锵声进行汇编,但甚至不
      LJMP8,start32
      。只有切换到AT&T语法并返回,我才能让clang的内置汇编程序(
      clang-m32-masm=intel-c
      )发出16位模式的远jmp

      .att_syntax
         ljmp $0x8, $start32      # working everywhere, even with clang
      .intel_syntax noprefix
      
      请记住,这种直接形式的far JMP在64位模式下不可用;也许这就是为什么LLVM的内置汇编器在这方面花费更少的精力



      脚注1:实际上,
      。英特尔语法前缀
      也可以,但永远不要使用它。没有人想看到弗兰肯怪物是
      mov%eax,[%eax]
      ,尤其是
      add%edx,%eax
      ,它使用的是
      dst,src
      顺序,但有AT&T修饰的寄存器名。

      你想要
      jmp 0x8:start32
      。PS:atat是《星球大战行者》,语法是at&t:)我的坏哈哈。使用jmp 0x8:start32会在表达式“Using GNU as.Assembly”之后生成“Error:junk”:start32,在这里使用
      as
      version 2.28可以很好地进行汇编。你有什么