首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >数据移动误差澄清

数据移动误差澄清
EN

Stack Overflow用户
提问于 2018-04-24 22:43:22
回答 2查看 2.1K关注 0票数 0

我目前正在解决的问题3.3从第三版的计算机系统:一个程序员的观点,我有一个困难的时间理解这些错误意味着.

movb $0xF, (%ebx)出现错误,因为ebx不能用作地址寄存器

movl %rax, (%rsp)movb %si, 8(%rbp)错误地指出指令后缀和寄存器I.D之间存在不匹配。

movl %eax, %rdx给出了一个错误,说明目标操作数大小不正确

为什么我们不能用ebx作为地址寄存器?是不是因为它的32位寄存器?如果是movb $0xF, (%rbx),下面的行会起作用吗?既然rbx是64位寄存器?

关于指令后缀与寄存器I.D之间不匹配的错误,是否出现此错误是因为它应该是movq %rax, (%rsp)movew %si, 8(%rbp),而不是movl %rax, (%rsp)movb %si, 8(%rbp)

最后,对于关于“目标操作数不正确的大小”的错误,是因为目标寄存器是64位而不是32位吗?所以,如果代码行是movl %eax, %edx,那么错误就不会发生吗?

任何开悟都会很感激。

这是x86-64的

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-04-25 01:57:00

代码语言:javascript
复制
movb $0xF, (%ebx) gives an error because ebx can't be used as address register

诚然,ebx不能用作地址寄存器(对于x86-64),但rbx可以。ebx是rbx的下32位。64位代码的全部要点是地址可以是64位,所以尝试使用32位寄存器来引用内存没有什么意义。

代码语言:javascript
复制
movl %rax, (%rsp) and movb %si, 8(%rbp) gives error saying that 
theres a mismatch between instruction suffix and register I.D.

是的,因为您使用的是movl,所以'l‘表示长,在这个上下文中)表示32位。然而,rax是一个64位寄存器。如果你想用rax写64位,你应该使用movq。如果你想写32位,你应该使用eax

代码语言:javascript
复制
movl %eax, %rdx gives an error saying that destination operand incorrect size

您正在尝试将32位值移动到64位寄存器中。有为您执行此转换的说明(例如,请参见cdq ),但movl不是其中之一。

票数 1
EN

Stack Overflow用户

发布于 2018-04-25 05:52:00

movb $0xF, (%ebx)可以很好地组装(带有0x67地址大小的前缀),如果ebx中的地址是有效的,则正确执行。

这可能是一个错误(例如,导致分段错误而无法截断指针),或者是次优,但如果你的书比这更有力(比如它不会组装),那么你的书就会出现错误。

您使用它而不是movb $0xF, (%rbx)的唯一原因是,%rbx的上字节是否可能包含垃圾,例如在x32 ABI (长模式下的ILP32)中,或者如果您是一个愚蠢的编译器,即当目标为32位指针模式时,始终使用地址大小的前缀,即使已知地址安全地为零扩展。

对于更常见的情况,32位地址大小对于x32 ABI非常有用,因为索引寄存器包含很高的垃圾,例如movl $0x12345, (%edi, %esi,4)

gcc -mx32可以在现实生活中轻松地发出movb $0xF, (%ebx)指令。(请注意,-mx32 (长模式下的32位指针)不同于-m32 (i386 ABI))。

代码语言:javascript
复制
int ext();          // can't inline
void foo(char *p) { 
    ext();          // clobbers arg-passing registers
    *p = 0xf;       // so gcc needs to save the arg for after the call
}

关于戈德波特编译器浏览器编译成

代码语言:javascript
复制
foo(char*):
    pushq   %rbx              # rbx is gcc's first choice of call-preserved reg.
    movq    %rdi, %rbx        # stupid gcc copies the whole 64 bits when only the low 32 are useful
    call    ext()
    movb    $15, (%ebx)       # $15 = $0xF
    popq    %rbx
    ret

mov $edi, %ebx会更好;IDK为什么gcc想要复制整个64位寄存器,当它将指针作为32位值处理时。不幸的是,x32 ABI从来没有真正在x86上流行,所以我想没有人花时间让gcc为它生成伟大的代码。

AArch64还提供了ILP32 ABI,以节省指针数据的内存/缓存占用,因此,如果AArch64 ILP32的任何工作改进了通常的跨体系结构部分,那么gcc在64位模式下的32位指针可能会更好(也有利于x86-64 )。

所以,如果代码行是movl %eax,%edx,那么错误不会发生吗?

对,这将使EAX零扩展到RDX。。如果您希望将EAX扩展为RDX,请使用)

(几乎)所有x86指令都要求它们的所有操作数都是相同的。(就操作数大小而言;许多指令都有一个形式,它有一个8位或32位的即期,它的符号扩展到64位或任何指令的操作数大小。例如,add $1, %eax将使用3字节表格.)

异常包括shl %cl, %eax和movzx/movsx。

在AT&T语法中,如果使用操作数大小的后缀,则寄存器的大小必须匹配.如果没有,寄存器就意味着操作数大小。mov %eax, %edxmovl是一样的。

内存+没有寄存器源或目标的即时指令需要显式大小:add $1, (%rdx)不会组装,因为操作数大小不明确,但是add %eax, (%rdx)是一个addl (32位操作数大小)。

movew %si, 8(%rbp)

不,movw %si, 8(%rbp)可以工作:P,但是请注意,如果您在函数条目上使用push %rbp / mov %rsp, %rbp创建了一个传统的堆栈框架,那么到8(%rbp)的存储将覆盖堆栈上返回地址的低16位。

但是,在x8664代码中,对于Windows或Linux,不需要%rbp指向那里,或者持有一个有效的指针。它只是一个调用保存寄存器,如%rbx,只要在返回之前恢复调用方的值,就可以用于任何您想要的东西。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50011697

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档