我目前正在解决的问题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的
发布于 2018-04-25 01:57:00
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位寄存器来引用内存没有什么意义。
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。
movl %eax, %rdx gives an error saying that destination operand incorrect size您正在尝试将32位值移动到64位寄存器中。有为您执行此转换的说明(例如,请参见cdq ),但movl不是其中之一。
发布于 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))。
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
}用关于戈德波特编译器浏览器编译成
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
retmov $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, %edx和movl是一样的。
内存+没有寄存器源或目标的即时指令需要显式大小: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,只要在返回之前恢复调用方的值,就可以用于任何您想要的东西。
https://stackoverflow.com/questions/50011697
复制相似问题