MOV & LEA
周银辉
注:下面的代码采用GAS风格, movl 与 leal 中的l是GAS后缀,表示操作数数“双字”类型的,你可以简单地理解成int。我将mov翻译成“加载”,接近“拷贝”的韵味,而不是直译的“移动”
1, movl 立即数 寄存器
将立即数加载到指定的寄存器,比如 movl $0x1234, %eax 则是将十六进制的0x1234加载到eax
2, movl 寄存器 寄存器
将寄存器的内容加载到另外一个寄存器中,比如 movl %ebx, %eax 则是将寄存器ebx中的内容拷贝一份到eax中
3, movl 内存 寄存器
将内存中的内容加载到寄存器中,比如 movl (%ebx), %eax 其先去ebx读取一个值,然后用这个值作为内存地址,到内存中加载实际内容到eax
4, movl 立即数 内存
将立即数加载到内存中去,比如 movl $0x1234, (%ebx) 其先去ebx读取一个值,然后用这个值作为内存地址, 然后将十六进制数0x1234加载进去
5, movl 寄存器 内存
将寄存器中内容加载到内存中去,比如 movl %ebx, (%eax) 其先去eax读取一个值,并将这个值作为内存地址,然后将ebx中的值加载到内存地址中去
注意到了吗?我没有列举 “movl 内存 内存”, 因为这是不合法的,如想将内存中内容加载到另一段内存,需要寄存器做中转。
另外,我们注意到,在mov指令中类似(%eax)这样的代码表示“将计算值作为内存地址,该地址处的内容”。那么 movl -12(%ebx, %ecx, 4), %eax 则应该理解成:将指针p所指向的内容(*p)加载到eax中,其中p所指向的地址是4*ecx+ebx-12, 注意,加载到eax中的是*p
如果,我想表达如下内容: “将指针p的值加载到eax中,其中p所指向的地址是4*ecx+ebx-12。注意,加载到eax中的是p” 应该怎么办呢 ? 这是lea该干的事。
LEA是load effective address的缩写,加载有效地址,即“将某个地址加载到寄存器”中
1, leal 立即数 寄存器
将立即数加载到寄存器中,比如 leal $0x1234, %eax 其和 movl $0x1234, %eax 的效果是一样的
2, leal 地址 寄存器
将地址加载到寄存器中,比如leal M, N 将M的有效地址加载到N中,效果可以理解成N<--&M
这里举几个例子说明:
leal (%ebx), %eax :其将(%ebx)在内存中的有效地址加载到eax中,但很巧的是,(%ebx)是一个间接寻址,其有效地址保存就在ebx中,所以这段代码与 movl %ebx, %eax具有相同的效果
leal 2(%ebx), %eax : 其中2(%ebx)这个间接寻址的有效地址为 %ebp+2, 那么这段代码的意思可以理解为:先从ebx中取出一个值,将这个值加上2,然后加载到eax中。
leal -12(ebx, ecx, 4), %eax : 答案上文找
注意到了吗?没有“leal 寄存器 寄存器”,因为是无法对寄存器去地址的。
另外,不要被“地址”以及“*p"之类的给迷惑了,在汇编层次他们都仅仅是一些”数“而已,比如:
leal (%ebx, %ebx, 4), %eax
假设ebx中的值是m, 那么上面的代码干的事情仅仅是:计算5*m并将结果放入eax 而已。(用这种方式计算5*m比用mul指令要节省时间一些)
来源:https://www.cnblogs.com/zhouyinhui/archive/2010/07/06/1772193.html