为什么要使用“movl $1, %eax”与“movb $1, %eax”相反
正如标题所述,为什么要使用“movl $1, %eax”而不是“movb $1, %eax”,有人告诉我 movl 会将 %eax 的高位清零,但事实并非如此%eax 是一个等于系统字长大小的寄存器吗?这意味着 movl 实际上是一个整数运算(而不是很长?)
我显然对这一切有点困惑;谢谢。
As the title states, why would one use "movl $1, %eax" as opposed to, say, "movb $1, %eax", I was told that movl would zero out the high order bits of %eax, but isn't %eax a register that's equivalent to the size of the system's wordsize? meaning that movl is in actuality an integer operation (and not a long?)
I'm clearly a bit confused about it all; Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这条指令是无效的。您不能将 eax 与 movb 指令一起使用。
您可以使用 8 位寄存器,或写入完整寄存器< /a> 的值在您关心的低字节中具有您想要的值。例如:
不。无论您处于哪种模式,EAX 始终是一个 32 位值。
您将 C 变量大小与寄存器大小混淆了。 C 变量大小可能会根据您的系统和编译器而变化。
汇编比C简单。在GAS AT&T汇编中,指令以字母“b”、“s”为后缀、“w”、“l”、“q”或“t”来确定正在操作的操作数的大小。 (或者寄存器操作数可以暗示一个大小,例如
mov $1, %eax
暗示movl
,这与mov $1, (%rdi)
不同 codeb
= 字节(8 位)s
= 单精度(32 位浮点),仅用于 x87 指令,例如flds (mem)
w
= 字(16 位)l
= long(32 位双字整数),或 x87 64 位浮点q
= 四元word(64 位)t
= 10 个字节(80 位浮点)这些大小永远不会改变。al 始终为 8 位,eax 始终为 32 位
。在 x86 术语中“字”始终为 16 位,并且在现代 x86 中与 CPU 或机器字大小的概念无关;x86 不是面向字的架构。
This instruction is invalid. You can't use eax with the movb instruction.
You would instead use an 8-bit register, or write the full register with a value that has the value you want in the low byte(s) you care about. For example:
No. EAX will always be a 32-bit value, regardless of what mode you're in.
You are confusing C variable sizes with register sizes. C variable sizes may change depending on your system and compiler.
Assembly is simpler than C. In GAS AT&T assembly, instructions are suffixed with the letters "b", "s", "w", "l", "q" or "t" to determine what size operand is being manipulated. (Or a register operand can imply a size, like
mov $1, %eax
impliesmovl
, unlike withmov $1, (%rdi)
which is ambiguous.b
= byte (8 bit)s
= single (32-bit floating point) used only for x87 instructions likeflds (mem)
w
= word (16 bit)l
= long (32 bit doubleword integer), or x87 64-bit floating pointq
= quad-word (64 bit)t
= ten bytes (80-bit floating point)These sizes are constant. They will never be changed. al is always 8-bits and eax is always 32-bits.
A "word" is always 16 bits in x86 terminology, and in modern x86 is unrelated to the concept of CPU or machine word size; x86 isn't a word-oriented architecture.
在 32 位机器上,%eax 是一个 4 字节(32 位)寄存器。 movl 将写入全部 4 个字节。在您的示例中,它将把高 3 个字节清零,并将 1 放入最低字节。 movb 只会更改低位字节。
On a 32 bit machine, %eax is a 4 byte (32 bit) register. movl will write into all 4 bytes. In your example, it'll zero out the upper 3 bytes, and put 1 in the lowest byte. The movb will just change the low order byte.
%eax
是一个 32 位寄存器。要使用较小的宽度,您需要 16 位的%ax
。%ax
又可以分为%ah
表示%ax
的高字节,%al
表示%ax
的高字节低字节。其他 x86 GPR 也是如此。查看
mov
指令的 Intel 指令集参考,我没有看到可以将单个字节移动到 32 位寄存器中的变体 - 它可能被解释为移动到%al
。由于 movl 是 32 位指令,因此在立即值的情况下,高字节的值将对应于零。如果您从内存中移动,您将移动整个 32 位字。
%eax
不会清零,除非您movl $0, %eax
或xorl %eax, %eax
。否则它会保留之前存在的任何值。当您movl $1, %eax
时,寄存器中最终会出现0x00000001
,因为 32 位指令将 32 位立即数移入寄存器。%eax
is a 32-bit register. To use a smaller width, you need%ax
for 16-bits.%ax
can be further divided into%ah
for the high byte of%ax
, and%al
for the lower byte. The same goes for the other x86 GPRs.Looking at the Intel instruction set reference for the
mov
instruction, I don't see a variant that can move a single byte into a 32-bit register -- it's probably interpreted as a move into%al
.Since
movl
is a 32-bit instruction, the values for the upper bytes will correspond to zeros in the case of an immediate value. If you were moving from memory you would be moving an entire 32-bit word.%eax
is not zeroed out unless you eithermovl $0, %eax
, or if youxorl %eax, %eax
. Otherwise it holds whatever value was previously in there. When youmovl $1, %eax
, you will end up with0x00000001
in the register because the 32-bit instruction moves a 32-bit immediate value into the register.long
最初是 32 位,而int
和short
是 16 位。并且操作码的名称不会每次有人提出时都改变一个新的操作系统。long
was originally 32 bits, whileint
andshort
were 16. And the names of the opcodes don't change every time someone comes out with a new operating system.你的第二个选择只会产生一个错误,x86 没有该指令。 X86 在将字节加载到某些寄存器方面有点独特。是的,在大多数指令集架构上,操作数为零或符号扩展,但 x86 允许您仅写入其中某些指令的低字节或低 16 位。
当然还有其他选择,例如清除寄存器然后递增它,但这里有三个最初看起来合理的选择:
第一个是 5 个字节,第二个是 4 个字节,第三个是 5 个字节。因此,如果优化,第二个是最佳选择为了空间,否则我认为最有可能跑得快的是第一个。如今,X86 已实现深度流水线化,因此两条指令将互锁,并且机器可能需要相当多的等待状态,具体取决于流水线硬件的详细信息。
当然,这些 x86 操作正在以特定于 CPU 的方式转换为CPU微操作,,所以谁知道会发生什么。
Your second choice will just produce an error, x86 doesn't have that instruction. X86 is a bit unique with respect to loading bytes into certain registers. Yes, on most instruction set architectures the operand is zero or sign-extended, but x86 allows you to write just the lower byte or lower 16 bits of some of them.
There are certainly other choices, like clearing the register and then incrementing it, but here are three initially reasonable-looking choices you have:
The first is 5 bytes, the second 4, the third 5. So the second is the best choice if optimizing for space, otherwise I suppose the one most likely to run fast is the first one. X86 is deeply pipelined these days, so the two instructions will interlock and the machine may need quite a few wait states depending on details of the pipeline hardware.
Of course, these x86 ops are being translated in CPU-specific ways into CPU micro-ops, and so who knows what will happen.
%eax
在 32 位机器上是 32 位。%ax
是16位,%ah
和%al
是它的8位高位和低位成分。因此 movl 在这里完全有效。从效率角度来看,
movl
将与movb
一样快,并且将%eax
的高 3 个字节清零通常是一个理想的属性。您稍后可能想将其用作 32 位值,因此 movb 并不是在那里移动字节的好方法。%eax
is 32 bits on 32-bit machines.%ax
is 16 bits, and%ah
and%al
are its 8-bit high and low constituents.Therefore
movl
is perfectly valid here. Efficiency-wise,movl
will be as fast asmovb
, and zeroing out the high 3 bytes of%eax
is often a desirable property. You might want to use it as a 32-bit value later, somovb
isn't a good way to move a byte there.