我正在使用 godbolt 来组装以下程序:
\n#include <stdio.h>\nvolatile int a = 5;\nvolatile int res = 0;\nint main() {\n res = a * 36;\n return 1;\n}\nRun Code Online (Sandbox Code Playgroud)\n如果我使用-Os优化,生成的代码很自然:
\nmov eax, DWORD PTR a[rip]\nimul eax, eax, 36\nmov DWORD PTR res[rip], eax\nRun Code Online (Sandbox Code Playgroud)\n但如果我使用-O2,生成的代码是这样的:
\nmov eax, DWORD PTR a[rip]\nlea eax, [rax+rax*8]\nsal eax, 2\nmov DWORD PTR res[rip], eax\nRun Code Online (Sandbox Code Playgroud)\n因此,它不是乘以 5*36,而是执行 5 -> 5+5*8=45 -> 45*4 = 180。我认为这是因为 1 imul 比 1 lea + 1 左移慢。
\n但在 lea 指令中,需要计算rax+rax*8,其中包含 1 个加法 …
我正在学习x86汇编,并且在lea指令上遇到了一些麻烦。
0x080486f7 <+21>: lea eax,[esp+0x18]
Run Code Online (Sandbox Code Playgroud)
谁能解释这行发生了什么?以我的理解,它将值取为[esp + 0x18]并将其解释为地址,然后将整数地址的值放入eax。
为了加深对"(*p)++"如何工作的印象,我写了一些测试代码,如:
int main()
{
int a = 3;
int *p = &a;
int b = (*p)++;
int *q = p++;
int c = a++;
int d = c++;
printf("a = %d, b = %d, c = %d, d = %d, p = %#x, q = %#x\n",a, b, c, d, p, q);
}
Run Code Online (Sandbox Code Playgroud)
输出为:a = 5,b = 3,c = 5,d = 4,p = 0xc6dc3490,q = 0xc6dc348c
但我的问题是关于装配(代码是订单而不是关闭和开启):
main:
push rbp
mov rbp, rsp
sub rsp, 48
;int a = 3 : …Run Code Online (Sandbox Code Playgroud) 我不完全理解前两行的含义,以及最后两行的区别.
LDS SI,[BX]
LES DI,[BX]
LEA DI,5000h
MOV DI,5000h
Run Code Online (Sandbox Code Playgroud)
我认为LEA在DI中加载5000h,MOV在DI中加载5000h的内容.我对吗??
我有一个内存位置,其中包含一个我想要与另一个角色进行比较的角色(并且它不在堆栈的顶部,所以我不能只是pop它).如何引用内存位置的内容以便进行比较?
基本上我如何在语法上做到这一点.
当我使用它们获取地址时,mov和lea之间究竟有什么区别?
假设我有一个程序从第5个字符开始打印出一个字符串,其代码如下所示:
section .text
global _start
_start:
mov edx, 0x06 ;the length of msg from its 5th char to the last is 6.
lea ecx, [msg + 4]
mov ebx, 1
mov eax, 4
int 0x80
section .data
msg db '1234567890'
Run Code Online (Sandbox Code Playgroud)
然后,如果我换lea ecx, [msg + 4]了mov ecx, msg + 4,将它运行不同?
我试过两个,输出看起来是一样的.但是,我从这个链接中读到,LEA指令的目的是什么?,在第一个答案的评论部分,似乎有人声称有类似mov ecx, msg + 4无效的东西,但我没有看到它.有人能帮助我理解这个吗?提前致谢!
我试图了解地址计算指令的工作原理,尤其是leaq命令.然后当我看到leaq用于进行算术运算的例子时,我感到困惑.例如,以下C代码,
long m12(long x) {
return x*12;
}
Run Code Online (Sandbox Code Playgroud)
在组装中
leaq (%rdi, %rdi, 2), %rax
salq $2, $rax
Run Code Online (Sandbox Code Playgroud)
如果我的理解是正确的,那么leaq应该移动任何(%rdi, %rdi, 2)应该2*%rdi+%rdi评估的地址%rax.我感到困惑的是,因为值x存储%rdi在内,这只是内存地址,为什么%rdi乘以3然后左移这个内存地址 2等于x乘以12?是不是当我们%rdi用3时,我们跳到另一个没有值x的内存地址?
leal(%eax,%ecx,4), %edx
Run Code Online (Sandbox Code Playgroud)
当我从我的计算机系统书中读到时,如果$ eax包含x值并且%ecx包含y,那么上面的意思是x + 4y放入%edx.
如果是的话
movl(%eax,%ecx,4), %edx
Run Code Online (Sandbox Code Playgroud)
那么上面的leal表达是不是同一个?
据我所知,leal创建了可以引用的地址,而不是像movl那样自己引用,但是
当我看到leal(%eax,%ecx,4), %edxequals x+4y进入edx注册时,那么t it mean that it 'referenced'%eax and%ecx`和提取值x和y用于计算?
这是如何工作的?我知道lea与使用add/mov指令相比是有效的,因为它不通过ALU或设置任何标志.那么lea如何得到它的地址呢?是什么让它比添加/ mov更好?
你为什么要用:
MOV EAX, 22
SHL EAX, 2
Run Code Online (Sandbox Code Playgroud)
...乘以4而不是仅仅使用MUL指令?
我知道这也可以用SHR而不是DIV.
这样做有什么好处?
你也可以用奇数做这个或者它只能是偶数吗?