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 将指令从eax移到es寄存器时出错_Assembly_X86_Nasm - Fatal编程技术网

Assembly 将指令从eax移到es寄存器时出错

Assembly 将指令从eax移到es寄存器时出错,assembly,x86,nasm,Assembly,X86,Nasm,我想不出一种方法来将代码从内存中的一个位置移动到另一个位置 所以我在某种程度上做了一些类似的事情,但它不起作用 extern _transfer_code_segment extern _kernel_segment extern _kernel_reloc extern _kernel_reloc_segment extern _kernel_para_size section .text16 global transfer_to_kernel

我想不出一种方法来将代码从内存中的一个位置移动到另一个位置

所以我在某种程度上做了一些类似的事情,但它不起作用

extern _transfer_code_segment

 extern _kernel_segment

  extern _kernel_reloc


 extern _kernel_reloc_segment

  extern _kernel_para_size


    section .text16



    global transfer_to_kernel




transfer_to_kernel:



    ;cld

    ;
    ; Turn off interrupts -- the stack gets destroyed during this routine.
    ; kernel must set up its own stack.
    ;
    ;cli
    ; stack for only for this function

    push ebp
    mov ebp, esp








    mov eax, _kernel_segment             ; source segment
    mov ebx, _kernel_reloc_segment       ; dest segment
    mov ecx, _kernel_para_size

.loop:



    ; XXX: Will changing the segment registers this many times have
    ; acceptable performance?


    mov ds, eax  ;this the place where the error
    mov es, ebx  ; this to
    xor esi, esi
    xor edi, edi
    movsd
    movsd
    movsd
    movsd
    inc eax
    inc ebx
    dec ecx
    jnz .loop



    leave
    ret

是否有其他方法来解决此问题,或者如何解决此问题

段寄存器的大小均为16位。将其与大小为32位的
e?x
寄存器进行比较。显然,这两个对象的大小不同,这会促使汇编程序生成一个“操作数大小不匹配”错误—两个操作数的大小不匹配

您可能希望使用寄存器的较低16位初始化段寄存器,因此您可以执行以下操作:

mov  ds, ax
mov  es, bx
另外,不,实际上不需要在循环的每次迭代中初始化段寄存器。现在要做的是增加段并强制偏移为0,然后复制4个DWORD。您应该做的是不使用段,只增加偏移量(这是
MOVSD
指令隐式执行的)

但请注意,将添加到
MOVSD
指令将允许您更高效地执行此操作。这基本上是
MOVSD
总共
ECX
次。例如:

mov ds, ax
mov es, bx
xor esi, esi
xor edi, edi
shl ecx, 2         ; adjust size since we're doing 1 MOVSD for each ECX, rather than 4
rep movsd
与直觉相反,如果处理器实现(英特尔常春藤网桥及更高版本),
REP MOVSB
可能实际上比
REP MOVSD
更快,因此您可以:

mov ds, ax
mov es, bx
xor esi, esi
xor edi, edi
shl ecx, 4
rep movsb
最后,尽管您已经注释掉了代码中的
CLD
指令,但您确实需要这样做,以确保移动按照计划进行。不能依赖具有特定值的方向标志;您需要自己将其初始化为所需的值


(另一种选择是数据流单指令多数据指令集(SIMD)指令,甚至浮点存储,两者都不关心方向标志。这有增加内存拷贝带宽的优点,因为一次要进行64位、128位或更大的拷贝,但会引入其他缺点。在内核中,我坚持使用
MOVSD
/
MOVSB
,除非您可以证明它不是一个重大瓶颈,并且/或者您希望为不同的处理器优化路径。)

段寄存器的大小都是16位。将其与大小为32位的
e?x
寄存器进行比较。显然,这两个寄存器的大小不相同,提示汇编程序生成“操作数大小不匹配”错误—两个操作数的大小不匹配

您可能希望使用寄存器的较低16位初始化段寄存器,因此您可以执行以下操作:

mov  ds, ax
mov  es, bx
此外,不需要,实际上不需要在循环的每次迭代中初始化段寄存器。现在要做的是增加段并强制偏移量为0,然后复制4个DWORD。应该做的是不使用段,而只是增加偏移量(这是
MOVSD
指令隐式执行的)

但请注意,将添加到
MOVSD
指令将允许您更有效地执行此操作。这基本上总共执行
MOVSD
次。例如:

mov ds, ax
mov es, bx
xor esi, esi
xor edi, edi
shl ecx, 2         ; adjust size since we're doing 1 MOVSD for each ECX, rather than 4
rep movsd
与直觉相反,如果处理器实现(英特尔常春藤网桥及更高版本),
REP MOVSB
可能实际上比
REP MOVSD
更快,因此您可以:

mov ds, ax
mov es, bx
xor esi, esi
xor edi, edi
shl ecx, 4
rep movsb
最后,虽然您已经注释掉了代码中的
CLD
指令,但您确实需要这样做,以确保移动按照计划进行。您不能依赖方向标志具有特定值;您需要自己将其初始化为所需的值


(另一种选择是数据流单指令多数据指令集(SIMD)指令,甚至浮点存储,两者都不关心方向标志。这有增加内存拷贝带宽的优点,因为一次要进行64位、128位或更大的拷贝,但会引入其他缺点。在内核中,我坚持使用
MOVSD
/
MOVSB
,除非您可以证明它不是一个重大瓶颈,并且/或者您希望为不同的处理器优化路径。)

这将有可怕的性能。说
mov sr,r
在Nehalem上每13个周期有一个吞吐量,我猜如果有什么问题的话,在最近的CPU上会更糟糕,因为分段已经过时。Agner在Nehalem之后停止测试mov到段寄存器/从段寄存器的性能

您这样做是为了让您复制的总容量超过64kiB吗?如果是这样,在更改段寄存器之前,至少要复制一个完整的64kiB

我认为您可以使用32位寻址模式来避免与段混淆,但在16位模式下设置的段隐式具有64k的“限制”(即
moveax,[esi]
可在16位模式下编码,具有操作数大小和地址大小前缀。但如果esi中的值大于0xFFFF,我认为违反
ds
段限制可能会出错。)请查看下面的osdev链接了解更多信息

正如Cody所说,使用
rep movsd
让CPU使用优化的微代码
memcpy
(。 实际上,使用
rep movsd
可能是最简单的方法,但IvyBridge可能不会。)它比separate
movsd
指令快得多(它比separate
mov
加载/存储慢得多).SSE 16B矢量加载/存储的循环速度可能与某些CPU上的
rep movsd
速度差不多,但不能在16位模式下对32B矢量使用AVX


大拷贝的另一个选项:巨大的非真实模式

在32位保护模式下,您在段中输入的值是描述符,而不是实际的段基本身。
mov es,ax
触发CPU使用该值作为GDT或LDT的索引,并从中获取段基/限制

如果在32位模式下执行此操作,然后切换回