You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MOVDQA与MOVDQU指令实验分析及技术疑问问询(x86/x64)

MOVDQA与MOVDQU指令特性探究及问题解答

参考链接

  • MOVDQU指令与页边界问题
  • MOVUPD vs MOVDQU(x86/x64汇编)
  • MOVDQA与MOVAPS x86指令的区别
  • 汇编"movdqa"访问违例
  • x86指令集文档:MOVDQA条目
  • x86指令集文档:MOVDQU条目

实验详情

以下实验基于64位Linux环境下的C++项目,探究MOVDQA与MOVDQU加载数据至XMM寄存器的特性:


初始化1

// Initialization 1
std::string_view lhs{"Once upon a time in Germany"}; // length = 27
std::string_view rhs = lhs.substr(20, 7);            // RHS points to "germany"

实验1.1

# Experiment 1.1
# Here: %rax = lhs, %rsi = rhs
movdqa (%rax), %xmm11           // SIGSEGV in this line, although it has enough memory allocations
movdqa (%rsi), %xmm12

实验1.2

# Experiment 1.2
# Here: %rax = lhs, %rsi = rhs
movdqu (%rax), %xmm11           // data successfully loaded into register
movdqu (%rsi), %xmm12           // data successfully loaded into register with some garbage

初始化2

// Initialization 2
void *lhs = mmap ( NULL, 27*sizeof(unsigned char), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 );
void *rhs = lhs + 20;

实验2.1

# Experiment 2.1
# Here: %rax = lhs, %rsi = rhs
movdqa (%rax), %xmm11           // data successfully loaded into register
movdqa (%rsi), %xmm12           // SIGSEGV in this line... Expected!

实验2.2

# Experiment 2.2
# Here: %rax = lhs, %rsi = rhs
movdqu (%rax), %xmm11           // data successfully loaded into register
movdqu (%rsi), %xmm12           // data successfully loaded into register with some garbage

初始化3

// Initialization 3
unsigned char *lhs = new unsigned char[27];
unsigned char *rhs = lhs + 20;

实验3.1

# Experiment 3.1
# Here: %rax = lhs, %rsi = rhs
movdqa (%rax), %xmm11           // data successfully loaded into register
movdqa (%rsi), %xmm12           // SIGSEGV in this line

实验3.2

# Experiment 3.2
# Here: %rax = lhs, %rsi = rhs
movdqu (%rax), %xmm11           // data successfully loaded into register
movdqu (%rsi), %xmm12           // data successfully loaded into register with some garbage

问题解答

1. 实验1.1中MOVDQA触发SIGSEGV的原因?

std::string_view指向的字符串字面量存储在进程的只读数据段(.rodata)。MOVDQA执行16字节对齐加载时,会尝试读取从lhs起始的连续16字节内存——原字符串长度为27字节,lhs起始的16字节虽包含有效数据,但该字符串字面量的后续内存可能未被分配,或属于只读数据段的无权限区域(比如刚好在页边界末尾,下一页未映射)。当MOVDQA尝试访问这些非法内存时,就会触发SIGSEGV。而MOVDQU支持非对齐加载,即使跨页只要目标页存在就不会触发异常,因此能成功加载(末尾补垃圾数据)。

2. MOVDQU并非绝对安全,哪些场景下会触发SIGSEGV?

MOVDQU虽支持非对齐访问,但只要加载操作涉及的任何内存页不存在、无对应访问权限,或地址超出进程地址空间范围,就会触发SIGSEGV,包括:

  • 加载的16字节数据中,部分字节位于未映射的内存页
  • 目标内存页被标记为PROT_NONE,或当前进程无读/写权限
  • 访问的地址超出进程虚拟地址空间的上下限

3. MOVDQA触发SIGSEGV的场景有哪些?

MOVDQA要求内存地址必须16字节对齐,且加载的所有内存都合法,触发SIGSEGV的场景包括:

  1. 地址未16字节对齐:x86架构中,非对齐的MOVDQA访问会直接触发一般保护异常(#GP),内核转为SIGSEGV
  2. 访问的内存页不存在/无权限:即使地址对齐,但加载的16字节跨页时,其中某页未映射、无访问权限,会触发SIGSEGV
  3. 越界访问合法页的权限外区域:比如对齐地址的16字节范围中,部分字节属于只读页但程序尝试写入(MOVDQA为加载指令,主要是读权限问题),或超出进程分配的内存范围

4. MOVDQA与MOVDQU的性能对比参考资料?

  • 官方优化手册:Intel® 64 and IA-32 Architectures Optimization Reference Manual、AMD Software Optimization Guide明确说明:地址对齐时,MOVDQA和MOVDQU性能几乎无差异;地址非对齐时,MOVDQU的性能略低于对齐的MOVDQA(老CPU差异更明显,Skylake及以后的新CPU中,非对齐访问的性能损耗已大幅降低)。
  • 实际测试数据:循环加载对齐内存时,两者吞吐量一致;加载非对齐内存时,MOVDQU的延迟比MOVDQA高1-3个周期(取决于CPU微架构)。

内容的提问来源于stack exchange,提问作者RajibTheKing

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 22:45:38