在x86-64 Tour of Intel Manuals中,我读到了
也许最令人惊讶的事实是,诸如
MOV EAX, EBX自动将指令的高32位归零的指令RAX.
同一来源引用的英特尔文档(3.4.1.1 64位手动基本架构中的通用寄存器)告诉我们:
- 64位操作数在目标通用寄存器中生成64位结果.
- 32位操作数生成32位结果,在目标通用寄存器中零扩展为64位结果.
- 8位和16位操作数生成8位或16位结果.目标通用寄存器的高56位或48位(分别)不会被操作修改.如果8位或16位操作的结果用于64位地址计算,则将寄存器显式符号扩展为完整的64位.
在x86-32和x86-64汇编中,16位指令如
mov ax, bx
Run Code Online (Sandbox Code Playgroud)
不要表现出这种"奇怪"的行为,即eax的上层词被归零.
因此:引入这种行为的原因是什么?乍一看似乎不合逻辑(但原因可能是我习惯了x86-32汇编的怪癖).
GCC 4.4.3生成了以下x86_64程序集.令我困惑的部分是mov %eax,%eax.将寄存器移到自身?为什么?
23b6c: 31 c9 xor %ecx,%ecx ; the 0 value for shift
23b6e: 80 7f 60 00 cmpb $0x0,0x60(%rdi) ; is it shifted?
23b72: 74 03 je 23b77
23b74: 8b 4f 64 mov 0x64(%rdi),%ecx ; is shifted so load shift value to ecx
23b77: 48 8b 57 38 mov 0x38(%rdi),%rdx ; map base
23b7b: 48 03 57 58 add 0x58(%rdi),%rdx ; plus offset to value
23b7f: 8b 02 mov (%rdx),%eax ; load map_used value to eax …Run Code Online (Sandbox Code Playgroud) x86汇编语言不得不改变,因为x86处理器架构已经从8位变为16位变为32位,现在变为64位.
我知道在32位汇编程序寄存器名称(EAX,EBX等)中,每个名称的E前缀代表扩展意味着32位形式的寄存器而不是16位形式(AX,BX等).
这些寄存器名称的R前缀在64位中代表什么?
我的计算机有64位处理器,并且当我寻找sizeof(int),sizeof(long)以及sizeof(long long),事实证明,INT和长为32位,和长长为64位.我研究了原因,看来普遍的假设是说C++ 中的int符合机器的字大小是错误的.据我所知,编译器需要定义大小,我的是Mingw-w64.我研究的原因是理解如果小于字大小的类型的使用有利于速度(例如,短与int)或它是否具有负面影响.在32位系统中,一种流行的观点是:由于字大小为int,short将被转换为int,这将导致额外的位移等,从而导致更差的性能.反对意见是缓存级别会有好处(我没有深入研究),使用short会对虚拟内存经济有用.所以,除了这种困境之间的混淆之外,我还面临着另一个问题.我的系统是64位,如果我使用int或short并不重要,它仍然会小于字大小,我开始认为使用64位长的长度不是很有效,因为它是在系统设计的级别.另外我读到还有另一个约束,即OS的库(ILP64,LP64),它定义了类型大小.在ILP64中,与LP64相比,默认int为64位,如果我使用支持ILP64的操作系统,它会加速程序吗?一旦我开始询问我应该使用哪种类型来加速我的C++程序,我就面临更深层次的主题,其中我没有专业知识,而且一些解释似乎相互矛盾.你能解释一下:
1)如果最佳做法是在x64中使用long long来实现最高性能,即使对于1-4字节数据也是如此?
2)使用小于字大小的类型(内存胜利与附加操作)的权衡
3)word和int size是64位的x64计算机是否有可能通过使用所谓的向后兼容性使用16位字大小来处理短路?或者它必须将16位文件放入64位文件中,并且可以完成的事实将系统定义为向后兼容.
4)我们可以强制编译器使int 64位?
5)如何将ILP64整合到使用LP64的PC中?
6)使用适用于其他编译器,操作系统和体系结构(32位处理器)的上述问题的代码可能存在哪些问题?
我对Linux内核的一个头文件(arch/x86/include/asm/nops.h)中的注释感到有些困惑.它说明了这一点
<...>以下指令在64位模式下不是nops,对于64位模式,使用K8或P6 nops而不是
movl%esi,%esi
leal 0x00(%esi),%esi
<...>
我想作者暗示机器指令(分别是'89 F6'和'8D 76 00')而不是汇编指令.根据LEA英特尔软件开发人员手册第2A卷中的描述,后一条指令(lea 0x00(%rsi), %esi)与前者相同,mov %esi,%esi.
所以这简化了问题,是否mov %esi,%esi实际上是x86-64上的无操作.
mov不会改变旗帜.这种mov也不会改变记忆.似乎,如果它改变了一些东西%rip,那应该是通用寄存器.但我不知道它如何改变内容%rsi或其他内容.如果你操纵通用寄存器的下半部分,上半部分不应该改变,对吧?
我在集会上总是一个菜鸟,只是捅了一下看看发生了什么.无论如何,我写了一个非常简单的函数:
void multA(double *x,long size)
{
long i;
for(i=0; i<size; ++i){
x[i] = 2.4*x[i];
}
}
Run Code Online (Sandbox Code Playgroud)
我编译它:
gcc -S -m64 -O2 fun.c
Run Code Online (Sandbox Code Playgroud)
我得到了这个:
.file "fun.c"
.text
.p2align 4,,15
.globl multA
.type multA, @function
multA:
.LFB34:
.cfi_startproc
testq %rsi, %rsi
jle .L1
movsd .LC0(%rip), %xmm1
xorl %eax, %eax
.p2align 4,,10
.p2align 3
.L3:
movsd (%rdi,%rax,8), %xmm0
mulsd %xmm1, %xmm0
movsd %xmm0, (%rdi,%rax,8)
addq $1, %rax
cmpq %rsi, %rax
jne .L3
.L1:
rep
ret
.cfi_endproc
.LFE34:
.size multA, .-multA
.section .rodata.cst8,"aM",@progbits,8
.align …Run Code Online (Sandbox Code Playgroud) 组装此代码时nasm:
BITS 64
mov eax, 0x1
mov rax, 0x1
Run Code Online (Sandbox Code Playgroud)
我得到这个输出:
b8 01 00 00 00 b8 01 00 00 00
Run Code Online (Sandbox Code Playgroud)
这是mov eax, 0x1重复两次的操作码.
这是否意味着mov rax, 0x1可以随时被替换mov eax, 0x1,或只是在这种情况下?
如果这是正确的,那么使用它不是更好:
xor rax, rax
inc rax
Run Code Online (Sandbox Code Playgroud)
因为组装时变为6个字节,而mov eax, 0x1只有5个字节?
这是复制(转换)未签名寄存器的指令:http : //www.felixcloutier.com/x86/MOVZX.html
基本上,该指令具有8-> 16、8-> 32、8-> 64、16-> 32和16-> 64。
32-> 64转换在哪里?我需要为此使用签名版本吗?
如果是这样,如何将全64位用于无符号整数?
assembly ×7
x86-64 ×7
gcc ×2
x86 ×2
32bit-64bit ×1
c++ ×1
cpu-word ×1
linux-kernel ×1
memory ×1
nasm ×1
performance ×1