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指令集

参考技术A

arm指令中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范围内。

参考技术B

arm指令中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] 处加载值。

另一方面,考虑表达式&amp;array[i]。这仍然包含子表达式array[i],但不执行解引用! array[i] 的含义已经改变。它不再意味着执行服从,而是充当一种规范,告诉&amp;我们正在寻找什么内存地址。如果您愿意,您也可以将&amp; 视为“取消”取消引用。

因为这两个用例在很多方面都很相似,所以它们共享语法 array[i],但 &amp; 的存在与否会改变该语法的解释方式。没有&amp;,它是一个取消引用,实际上是从数组中读取的。对于&amp;,它不是。 array + i * sizeof(long) 的值仍在计算中,但并未取消引用。

movlea 的情况非常相似。使用mov,会发生lea 不会发生的取消引用。尽管在两者中都使用了括号。例如,movq (%r8), %r9leaq (%r8), %r9。对于mov,这些括号表示“取消引用”;与lea,他们没有。这类似于array[i] 在没有&amp; 时仅表示“取消引用”。

举个例子。

考虑代码

movq (%rdi, %rsi, 8), %rbp

这会将内存位置%rdi + %rsi * 8 的值加载到寄存器%rbp 中。即:获取寄存器%rdi中的值和寄存器%rsi中的值。将后者乘以 8,然后将其与前者相加。 找到该位置的值并将其放入寄存器%rbp

这段代码对应于C行x = array[i];,其中array变成%rdii变成%rsix变成%rbp8 是数组中包含的数据类型的长度。

现在考虑使用lea的类似代码:

leaq (%rdi, %rsi, 8), %rbp

正如movq 的使用对应于解引用,leaq 的使用在这里对应 解引用。这一行汇编对应于C行x = &amp;array[i];。回想一下&amp;array[i] 的含义从取消引用更改为简单地指定位置。同样,leaq 的使用将 (%rdi, %rsi, 8) 的含义从取消引用更改为指定位置。

这行代码的语义如下:获取寄存器%rdi中的值和寄存器%rsi中的值。将后者乘以 8,然后将其与前者相加。将此值放入寄存器%rbp。不涉及内存加载,仅涉及算术运算 [2]。

请注意,我对leaqmovq 的描述之间的唯一区别是movq 进行了取消引用,而leaq 没有。其实写leaq的描述,我基本上是复制+粘贴movq的描述,然后去掉“在这个位置找值”。

总结一下:movqleaq 比较棘手,因为它们处理括号的使用方式不同,如 (%rsi)(%rdi, %rsi, 8)。在movq(以及除lea 之外的所有其他指令)中,这些括号表示真正的取消引用,而在leaq 中,它们不是并且纯粹是方便的语法。


[1] 我说过当arraylong 的数组时,表达式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 的 &amp; 运算符是一个很好的类比。或许值得指出的是,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 有时用于将寄存器相加或相乘,而无需使用显式的 ADDMUL 指令(或等效指令)。

由于每个人都在展示 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有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

ARM指令和THUMB指令有啥区别

ARM汇编中LDR伪指令和LDR指令

80C51指令系统中Rn与Ri有啥区别?

ARM指令adr adrl ldr mov

ARM汇编指令

004.ARM指令之LDR