arm指令中mov和ldr有啥区别?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了arm指令中mov和ldr有啥区别?相关的知识,希望对你有一定的参考价值。
如题.
1、两者含义不同
Mov只能在寄存器之间移动数据,或将立即数移到寄存器中。x86中没有LDR指令,因为x86的MOV指令可以将数据从内存移动到寄存器,但也有LDR伪指令。
尽管LDR伪指令与arm的LDR指令非常相似,但它们具有不同的功能,LDR伪指令可以在immediate之前加=来指示地址已写入寄存器。
2、两者功能不同
Mov为寄存器分配立即数,但需要立即数范围,它只能是8位连续有效位通过偶数移位得到的数。如果立即数超出此范围,则无法使用MOV指令将值赋给寄存器,除了普通的读数外,LDR还具有给寄存器分配立即数的功能。
扩展资料:
1、LDR指令
LDR指令的格式为:LDR条件 目的寄存器,<存储器地址>
LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。
当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。该指令在程序设计中比较常用,且寻址方式灵活多样。
指令示例:
LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0。
LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0。
LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0。
LDR R0,[R1,R2] ! ;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1,#8] ! ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1。
LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1,R2,LSL#2]! ;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDR R0,[R1],R2,LSL#2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
2、MOV指令
MOV 数据传送指令格式:MOV<cond>S <Rd>,<op1>;
功能:Rd=op1
op1可以是寄存器、被移位的寄存器或立即数。
例如:
MOV R0,#5 ;R0=5
MOV R0,R1 ;R0=R1
MOV R0,R1,LSL#5 ;R0=R1左移5位
参考资料来源:百度百科-ARM指令集
参考技术Aarm指令中mov和ldr的区别:
1、两者含义不同
Mov只能在寄存器之间移动数据,或将立即数移到寄存器中。
x86中没有LDR指令,因为x86的MOV指令可以将数据从内存移动到寄存器,但也有LDR伪指令。尽管LDR伪指令与arm的LDR指令非常相似,但它们具有不同的功能,LDR伪指令可以在immediate之前加=来指示地址已写入寄存器。
2、两者功能不同
Mov为寄存器分配立即数,但需要立即数范围,它只能是8位连续有效位通过偶数移位得到的数。如果立即数超出此范围,则无法使用MOV指令将值赋给寄存器,除了普通的读数外,LDR还具有给寄存器分配立即数的功能。
扩展资料:
LDR指令示例:
LDR R0,[R1];将存储器地址为R1的字数据读入寄存器R0。
LDR R0,[R1,R2];将存储器地址为R1+R2的字数据读入寄存器R0。
LDR R0,[R1,ා8];将存储器地址为R1+8的字数据读入寄存器R0。
LDR R0,[R1],R2;将内存地址为R1的字数据读入寄存器R0,并将R1+R2的值存储到R1中。
LDR R0,[R1],ා8;将存储器地址为R1的字数据读入寄存器R0,并将R1+8的值存储到R1中。
LDR R0,[R1,R2]!;将存储器地址为R1+R2的字数据读入寄存器R0,并将R1+R2的值存储到R1。
LDR R0,[R1,LSLා3];将存储器地址为R1*8的字数据读入寄存器R0。
LDR R0,[R1,R2,LSL 2];将存储器地址为R1+R2*4的字数据读入寄存器R
LDR R0,[R1,R2,LSL#2]!;将存储器地址为R1+R2*4的字数据读入寄存器R0,并将R1+R2*4的值存储到R1。
LDR R0,[R1],R2,LSL×2;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2*4的值存储到R1中。
LDR R0,label;label是程序标签,标签必须在当前指令的-4~4KB范围内。
参考技术Barm指令中mov和ldr的区别:
1、两者含义不同
mov只能在寄存器之间移动数据,或者把立即数移动到寄存器中。
x86中没有ldr这种指令,因为x86的mov指令可以将数据从内存中移动到寄存器中。但是有ldr伪指令,虽然ldr伪指令和ARM的ldr指令很像,但是作用不太一样。ldr伪指令可以在立即数前加上=,以表示把一个地址写到某寄存器中。
2、两者功能不同
Mov 是把立即数赋给一个寄存器,但对立即数的范围有要求。只能是由 8bit 连续有效位通过偶数次
移位能得到的数。如果立即数超出这个范围,就没办法用一条 MOV 指令给寄存器赋值。
LDR 除了普通的读数之外,也有给寄存器赋立即数的功能。
扩展资料:
LDR指令示例:
LDR R0,[R1];将存储器地址为R1的字数据读入寄存器R0。
LDR R0,[R1,R2];将存储器地址为R1+R2的字数据读入寄存器R0。
LDR R0,[R1,#8];将存储器地址为R1+8的字数据读入寄存器R0。
LDR R0,[R1],R2;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2的值存入R1。
LDR R0,[R1],#8;将存储器地址为R1的字数据读入寄存器R0,并将R1+8的值存入R1。
LDR R0,[R1,R2]!;将存储器地址为R1+R2的字数据读入寄存器R0,并将R1+R2的值存入R1。
LDR R0,[R1,LSL #3] ;将存储器地址为R1*8的字数据读入寄存器R0。
LDR R0,[R1,R2,LSL #2];将存储器地址为R1+R2*4的字数据读入寄存器R0。
LDR R0,[R1,,R2,LSL #2]!;将存储器地址为R1+R2*4的字数据读入寄存器R0,并将R1+R2*4的值存入R1。
LDR R0,[R1],R2,LSL #2 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2*4的值存入R1。
LDR R0,Label ;Label为程序标号,Label必须是当前指令的-4~4KB范围内。
参考资料来源:百度百科--arm指令集
参考技术C ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。比如想把数据从内存中某处读取到寄存器中,只能使用ldr
比如:
ldr r0, 0x12345678
就是把0x12345678这个地址中的值存放到r0中。
而mov不能干这个活,mov只能在寄存器之间移动数据,或者把立即数移动到寄存器中,这个和x86这种CISC架构的芯片区别最大的地方。
x86中没有ldr这种指令,因为x86的mov指令可以将数据从内存中移动到寄存器中。
另外还有一个就是ldr伪指令,虽然ldr伪指令和ARM的ldr指令很像,但是作用不太一样。ldr伪指令可以在立即数前加上=,以表示把一个地址写到某寄存器中,比如:
ldr r0, =0x12345678
这样,就把0x12345678这个地址写到r0中了。所以,ldr伪指令和mov是比较相似的。只不过mov指令限制了立即数的长度为8位,也就是不能超过512。而ldr伪指令没有这个限制。如果使用ldr伪指令时,后面跟的立即数没有超过8位,那么在实际汇编的时候该ldr伪指令是被转换为mov指令的。
ldr伪指令和ldr指令不是一个同东西。本回答被提问者采纳 参考技术D MOV和LDR的区别,数据从内存到CPU之间的移动只能通过LDR/STR指令来完成,MOV只能在寄存器之间移动数据,或者把立即数移动到寄存器中。
MOV和LEA有啥区别?
【中文标题】MOV和LEA有啥区别?【英文标题】:What is the difference between MOV and LEA?MOV和LEA有什么区别? 【发布时间】:2010-12-14 13:25:23 【问题描述】:我想知道这些指令有什么区别:
MOV AX, [TABLE-ADDR]
和
LEA AX, [TABLE-ADDR]
【问题讨论】:
重复:***.com/questions/1658294/… 谢谢尼克。首先,通过查看该链接,我不会找到这个问题的答案。在这里我正在寻找特定信息,您提供的链接中的讨论本质上更一般。 我很久以前就支持@Nick 的 dup,但现在才支持。回想起来,我太仓促了,现在天真地认为a)另一个问题没有回答“有什么区别”,b)这是一个有用的问题。为我的错误向天真道歉 - 如果我能撤消 vtc... LEA 与添加:***.com/questions/6323027/lea-or-add-instruction 相关:Using LEA on values that aren't addresses / pointers? 谈论 LEA 的其他用途,用于任意数学。 【参考方案1】:LEA
表示加载有效地址
MOV
表示加载值
简而言之,LEA
加载指向您正在寻址的项目的指针,而 MOV 加载该地址处的实际值。
LEA
的目的是允许人们执行非平凡的地址计算并存储结果[供以后使用]
LEA ax, [BP+SI+5] ; Compute address of value
MOV ax, [BP+SI+5] ; Load value at that address
在只涉及常量的情况下,MOV
(通过汇编程序的常量计算)有时会与LEA
的最简单使用情况重叠。如果您有多个基地址等的多部分计算,它很有用。
【讨论】:
+1 感谢您的清晰解释,帮助我answer 另一个问题。 让我感到困惑的是 lea 在名称中包含“加载”,人们说它将计算的地址“加载”到寄存器中,因为计算内存位置的所有输入都是立即值或寄存器. AFAICT lea 只执行计算,它不加载任何东西,加载意味着接触内存? @josephGarvin IIRC 术语 fetch 将应用于该方面;加载就是你如何用从头开始的东西替换寄存器中的值。例如LAHF
是:将 FLAGS 加载到 AH 寄存器中。在 CLR 的 CIL(它是一个更高级别的基于堆栈的抽象机,术语 load 是指将一个值放到概念堆栈上,通常是 l
... 和 s
。 ..等价的反之亦然)。这些注释:cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/load.html) 表明确实存在适用于您的区别的架构。
这一切让我想起了slideshare.net/pirhilton/… ;)【参考方案2】:
在 NASM 语法中:
mov eax, var == lea eax, [var] ; i.e. mov r32, imm32
lea eax, [var+16] == mov eax, var+16
lea eax, [eax*4] == shl eax, 2 ; but without setting flags
在 MASM 语法中,使用 OFFSET var
获取 mov-immediate 而不是加载。
【讨论】:
仅在 NASM 语法中。在 MASM 语法中,mov eax, var
是一个负载,与mov eax, [var]
相同,您必须使用mov eax, OFFSET var
才能将标签用作立即常量。
清晰、简单,并演示了我试图确认的内容。谢谢。
请注意,在所有这些示例中,lea
是更糟糕的选择,除了用于 RIP 相对寻址的 64 位模式。 mov r32, imm32
在更多端口上运行。 lea eax, [edx*4]
是一种复制和移位,否则无法在一条指令中完成,但在同一个寄存器中,LEA 只需要更多字节来编码,因为[eax*4]
需要disp32=0
。 (不过,它运行在与班次不同的端口上。)请参阅 agner.org/optimize 和 ***.com/tags/x86/info。【参考方案3】:
MOV reg,addr 指令将地址addr 处的变量读入寄存器reg。指令 LEA reg,addr 表示将地址(不是该地址存储的变量)读入寄存器 reg。
MOV 指令的另一种形式是 MOV reg,immdata,这意味着将立即数(即常量) immdata 读入寄存器 reg。请注意,如果 LEA reg,addr 中的 addr 只是一个常数(即固定偏移量),则该 LEA 指令本质上与加载与立即数据相同的常数的等效 MOV reg,immdata 指令完全相同。
【讨论】:
【参考方案4】:之前的答案都没有完全解决我自己的困惑,所以我想添加自己的答案。
我缺少的是lea
操作处理括号的使用与mov
不同。
想想 C。假设我有一个 long
数组,我称之为 array
。现在表达式array[i]
执行解引用,从内存地址array + i * sizeof(long)
[1] 处加载值。
另一方面,考虑表达式&array[i]
。这仍然包含子表达式array[i]
,但不执行解引用! array[i]
的含义已经改变。它不再意味着执行服从,而是充当一种规范,告诉&
我们正在寻找什么内存地址。如果您愿意,您也可以将&
视为“取消”取消引用。
因为这两个用例在很多方面都很相似,所以它们共享语法 array[i]
,但 &
的存在与否会改变该语法的解释方式。没有&
,它是一个取消引用,实际上是从数组中读取的。对于&
,它不是。 array + i * sizeof(long)
的值仍在计算中,但并未取消引用。
mov
和lea
的情况非常相似。使用mov
,会发生lea
不会发生的取消引用。尽管在两者中都使用了括号。例如,movq (%r8), %r9
和 leaq (%r8), %r9
。对于mov
,这些括号表示“取消引用”;与lea
,他们没有。这类似于array[i]
在没有&
时仅表示“取消引用”。
举个例子。
考虑代码
movq (%rdi, %rsi, 8), %rbp
这会将内存位置%rdi + %rsi * 8
的值加载到寄存器%rbp
中。即:获取寄存器%rdi
中的值和寄存器%rsi
中的值。将后者乘以 8,然后将其与前者相加。 找到该位置的值并将其放入寄存器%rbp
。
这段代码对应于C行x = array[i];
,其中array
变成%rdi
,i
变成%rsi
,x
变成%rbp
。 8
是数组中包含的数据类型的长度。
现在考虑使用lea
的类似代码:
leaq (%rdi, %rsi, 8), %rbp
正如movq
的使用对应于解引用,leaq
的使用在这里对应不 解引用。这一行汇编对应于C行x = &array[i];
。回想一下&
将array[i]
的含义从取消引用更改为简单地指定位置。同样,leaq
的使用将 (%rdi, %rsi, 8)
的含义从取消引用更改为指定位置。
这行代码的语义如下:获取寄存器%rdi
中的值和寄存器%rsi
中的值。将后者乘以 8,然后将其与前者相加。将此值放入寄存器%rbp
。不涉及内存加载,仅涉及算术运算 [2]。
请注意,我对leaq
和movq
的描述之间的唯一区别是movq
进行了取消引用,而leaq
没有。其实写leaq
的描述,我基本上是复制+粘贴movq
的描述,然后去掉“在这个位置找值”。
总结一下:movq
与 leaq
比较棘手,因为它们处理括号的使用方式不同,如 (%rsi)
和 (%rdi, %rsi, 8)
。在movq
(以及除lea
之外的所有其他指令)中,这些括号表示真正的取消引用,而在leaq
中,它们不是并且纯粹是方便的语法。
[1] 我说过当array
是long
的数组时,表达式array[i]
会从地址array + i * sizeof(long)
加载值。这是真的,但有一个微妙之处需要解决。如果我写 C 代码
long x = array[5];
这不和打字一样
long x = *(array + 5 * sizeof(long));
似乎应该根据我之前的说法,其实不是。
发生的事情是 C 指针加法有一个技巧。假设我有一个指针p
指向T
类型的值。表达式p + i
确实不是的意思是“p
的位置加上i
字节”。相反,表达式p + i
实际上 的意思是“p
的位置加上i * sizeof(T)
字节”。
这样做的方便之处在于,要获得“下一个值”,我们只需编写 p + 1
而不是 p + 1 * sizeof(T)
。
这意味着C代码long x = array[5];
实际上等价于
long x = *(array + 5)
因为 C 会自动将 5
乘以 sizeof(long)
。
那么在这个 *** 问题的上下文中,这一切有什么关系?这意味着当我说“地址array + i * sizeof(long)
”时,我确实不是意味着将“array + i * sizeof(long)
”解释为C 表达式。我自己乘以 sizeof(long)
是为了让我的答案更明确,但请理解,因此,这个表达式不应被解读为 C。就像使用 C 语法的普通数学一样。
[2] 旁注:因为所有lea
所做的都是算术运算,所以它的参数实际上不必引用有效地址。出于这个原因,它通常用于对可能不打算取消引用的值执行纯算术运算。例如,cc
和 -O2
优化转换
long f(long x)
return x * 5;
进入以下(不相关的行已删除):
f:
leaq (%rdi, %rdi, 4), %rax # set %rax to %rdi + %rdi * 4
ret
【讨论】:
是的,很好的解释,比其他答案更详细,是的 C 的&
运算符是一个很好的类比。或许值得指出的是,LEA 是一种特殊情况,而 MOV 就像其他可以获取内存或寄存器操作数的指令一样。例如add (%rdi), %eax
只是使用寻址模式来寻址内存,与 MOV 相同。也相关:Using LEA on values that aren't addresses / pointers? 进一步解释:LEA 是您如何使用 CPU 对地址数学的硬件支持来进行任意计算。
"get the value at %rdi
" -- 这个措辞很奇怪。您的意思是应该使用寄存器中的值 rdi
。您对“at”的使用似乎意味着没有内存引用。
@PeterCordes 谢谢!我已经在答案中添加了关于它是特例的观点。
@ecm 好点;我没有注意到这一点。我现在改了,谢谢! :)
最后一个技巧真是太棒了。编译器在提高 exe 效率方面确实做得很好。【参考方案5】:
如果只指定文字,则没有区别。不过,LEA 具有更多功能,您可以在此处了解它们:
http://www.oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-1.html#HEADING1-136
【讨论】:
我猜,除了在 GNU 汇编器中,当涉及到 .bss 段中的标签时,它不是真的? AFAIR 你真的不能leal TextLabel, LabelFromBssSegment
当你得到smth。像.bss .lcomm LabelFromBssSegment, 4
,你必须movl $TextLabel, LabelFromBssSegment
,不是吗?
@JSmyth:那只是因为lea
需要一个寄存器目标,但mov
可以有一个imm32
源和一个内存目标。这个限制当然不是特定于 GNU 汇编器的。
另外,这个答案基本上是错误的,因为问题是询问MOV AX, [TABLE-ADDR]
,这是一个负担。所以有很大的不同。等效指令为mov ax, OFFSET table_addr
链接已失效。【参考方案6】:
这取决于使用的汇编程序,因为
mov ax,table_addr
在 MASM 中作为
mov ax,word ptr[table_addr]
所以它从table_addr
加载第一个字节,而不是table_addr
的偏移量。你应该改用
mov ax,offset table_addr
或
lea ax,table_addr
效果相同。
lea
版本也可以在 table_addr
是局部变量时正常工作,例如
some_procedure proc
local table_addr[64]:word
lea ax,table_addr
【讨论】:
非常感谢,只是我不能将多个标记为答案:( x86 指令 MOV 和 LEA 之间的区别绝对不取决于汇编程序。【参考方案7】:如其他答案所述:
MOV
将在括号内的地址处获取 数据,并将该 数据 放入目标操作数中。
LEA
将执行括号内地址的计算,并将 计算的地址 放入目标操作数。这发生在没有真正进入内存并获取数据的情况下。 LEA
所做的工作是计算“有效地址”。
由于内存可以通过多种不同的方式寻址(参见下面的示例),LEA
有时用于将寄存器相加或相乘,而无需使用显式的 ADD
或 MUL
指令(或等效指令)。
由于每个人都在展示 Intel 语法的示例,以下是一些 AT&T 语法:
MOVL 16(%ebp), %eax /* put long at ebp+16 into eax */
LEAL 16(%ebp), %eax /* add 16 to ebp and store in eax */
MOVQ (%rdx,%rcx,8), %rax /* put qword at rcx*8 + rdx into rax */
LEAQ (%rdx,%rcx,8), %rax /* put value of "rcx*8 + rdx" into rax */
MOVW 5(%bp,%si), %ax /* put word at si + bp + 5 into ax */
LEAW 5(%bp,%si), %ax /* put value of "si + bp + 5" into ax */
MOVQ 16(%rip), %rax /* put qword at rip + 16 into rax */
LEAQ 16(%rip), %rax /* add 16 to instruction pointer and store in rax */
MOVL label(,1), %eax /* put long at label into eax */
LEAL label(,1), %eax /* put the address of the label into eax */
【讨论】:
对于绝对的[disp32]
寻址模式,您永远不需要lea label, %eax
。请改用mov $label, %eax
。是的,它有效,但效率较低(更大的机器代码并在更少的执行单元上运行)。既然你提到了 AT&T,Using LEA on values that aren't addresses / pointers? 使用 AT&T,我的回答还有其他一些 AT&T 示例。【参考方案8】:
基本上……“在计算之后移入 REG……” 其他用途似乎也不错:)
如果你忘记了这个值是一个指针 您可以将其用于代码优化/最小化......无论怎样......
MOV EBX , 1
MOV ECX , 2
;//with 1 instruction you got result of 2 registers in 3rd one ...
LEA EAX , [EBX+ECX+5]
EAX = 8
原来是这样的:
MOV EAX, EBX
ADD EAX, ECX
ADD EAX, 5
【讨论】:
是的,lea
is a shift-and-add instruction 使用内存操作数机器编码和语法,因为硬件已经知道如何解码 ModR/M + SIB + disp0/8/32。【参考方案9】:
让我们通过一个例子来理解这一点。
mov eax, [ebx] 和
lea eax, [ebx] 假设 ebx 中的值为 0x400000。然后 mov 将转到地址 0x400000 并将它们的 4 字节数据复制到 eax 寄存器。而 lea 将地址 0x400000 复制到 eax。所以,每条指令执行后,每种情况下eax的值都会是(假设在内存0x400000包含的是30)。
eax = 30(在 mov 的情况下) eax = 0x400000(如果是 lea) 对于定义,mov将数据从rm32复制到目标(mov dest rm32),lea(加载有效地址)将地址复制到目标(mov dest rm32)。
【讨论】:
【参考方案10】:MOV 可以做与 LEA [label] 相同的事情,但 MOV 指令包含指令本身内部的有效地址作为立即常数(由汇编程序预先计算)。 LEA 在指令执行过程中使用 PC-relative 计算有效地址。
【讨论】:
这仅适用于 64 位模式(PC 相对寻址是新的);在其他模式下lea [label
与更紧凑的mov
相比,浪费字节是毫无意义的,因此您应该指定您正在谈论的条件。此外,对于某些汇编程序,[label]
不是 RIP 相对寻址模式的正确语法。但是,是的,这是准确的。 How to load address of function or label into register in GNU Assembler 解释更详细。【参考方案11】:
LEA(加载有效地址)是移位加指令。它被添加到 8086 是因为有硬件来解码和计算寻址模式。
【讨论】:
【参考方案12】:区别很微妙但很重要。 MOV 指令是一个“MOVe”,实际上是 TABLE-ADDR 标签所代表的地址的副本。 LEA 指令是“加载有效地址”,它是一条间接指令,这意味着 TABLE-ADDR 指向要加载的地址所在的内存位置。
有效地使用 LEA 相当于在 C 等语言中使用指针,因为它是一个强大的指令。
【讨论】:
我认为这个答案充其量是令人困惑的。 “LEA 指令是一条‘加载有效地址’,它是一条间接指令,这意味着 TABLE-ADDR 指向找到要加载的地址的内存位置。”实际上 LEA 将加载地址,而不是地址的内容。我认为实际上需要向提问者保证 MOV 和 LEA 可以重叠,并且在某些情况下做完全相同的事情以上是关于arm指令中mov和ldr有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章