R__*_*R__ 26 x86 assembly gnu-assembler att
0x0000000000400553 <main+59>: mov -0x4(%rbp),%eax
0x0000000000400556 <main+62>: cltq
0x0000000000400558 <main+64>: shl $0x3,%rax
0x000000000040055c <main+68>: mov %rax,%rdx
Run Code Online (Sandbox Code Playgroud)
事实上,我的程序很简单:
5 int main(int argc, char *argv[]) {
6 int i = 0;
7 while(environ[i]) {
8 printf("%s\n", environ[i++]);
9 }
10 return 0;
Run Code Online (Sandbox Code Playgroud)
但是程序集输出很长:
Dump of assembler code for function main:
0x0000000000400518 <main+0>: push %rbp
0x0000000000400519 <main+1>: mov %rsp,%rbp
0x000000000040051c <main+4>: sub $0x20,%rsp
0x0000000000400520 <main+8>: mov %edi,-0x14(%rbp)
0x0000000000400523 <main+11>: mov %rsi,-0x20(%rbp)
0x0000000000400527 <main+15>: movl $0x0,-0x4(%rbp)
0x000000000040052e <main+22>: jmp 0x400553 <main+59>
0x0000000000400530 <main+24>: mov -0x4(%rbp),%eax
0x0000000000400533 <main+27>: cltq
0x0000000000400535 <main+29>: shl $0x3,%rax
0x0000000000400539 <main+33>: mov %rax,%rdx
0x000000000040053c <main+36>: mov 0x2003e5(%rip),%rax # 0x600928 <environ@@GLIBC_2.2.5>
0x0000000000400543 <main+43>: lea (%rdx,%rax,1),%rax
0x0000000000400547 <main+47>: mov (%rax),%rdi
0x000000000040054a <main+50>: addl $0x1,-0x4(%rbp)
0x000000000040054e <main+54>: callq 0x400418 <puts@plt>
0x0000000000400553 <main+59>: mov -0x4(%rbp),%eax
0x0000000000400556 <main+62>: cltq
0x0000000000400558 <main+64>: shl $0x3,%rax
0x000000000040055c <main+68>: mov %rax,%rdx
0x000000000040055f <main+71>: mov 0x2003c2(%rip),%rax # 0x600928 <environ@@GLIBC_2.2.5>
0x0000000000400566 <main+78>: lea (%rdx,%rax,1),%rax
0x000000000040056a <main+82>: mov (%rax),%rax
0x000000000040056d <main+85>: test %rax,%rax
0x0000000000400570 <main+88>: jne 0x400530 <main+24>
0x0000000000400572 <main+90>: mov $0x0,%eax
0x0000000000400577 <main+95>: leaveq
0x0000000000400578 <main+96>: retq
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)
我不明白的是这个块:
0x000000000040052e <main+22>: jmp 0x400553 <main+59>
0x0000000000400530 <main+24>: mov -0x4(%rbp),%eax
0x0000000000400533 <main+27>: cltq
0x0000000000400535 <main+29>: shl $0x3,%rax
0x0000000000400539 <main+33>: mov %rax,%rdx
0x000000000040053c <main+36>: mov 0x2003e5(%rip),%rax # 0x600928 <environ@@GLIBC_2.2.5>
0x0000000000400543 <main+43>: lea (%rdx,%rax,1),%rax
0x0000000000400547 <main+47>: mov (%rax),%rdi
0x000000000040054a <main+50>: addl $0x1,-0x4(%rbp)
0x000000000040054e <main+54>: callq 0x400418 <puts@plt>
0x0000000000400553 <main+59>: mov -0x4(%rbp),%eax
0x0000000000400556 <main+62>: cltq
0x0000000000400558 <main+64>: shl $0x3,%rax
0x000000000040055c <main+68>: mov %rax,%rdx
0x000000000040055f <main+71>: mov 0x2003c2(%rip),%rax # 0x600928 <environ@@GLIBC_2.2.5>
0x0000000000400566 <main+78>: lea (%rdx,%rax,1),%rax
0x000000000040056a <main+82>: mov (%rax),%rax
0x000000000040056d <main+85>: test %rax,%rax
0x0000000000400570 <main+88>: jne 0x400530 <main+24>
Run Code Online (Sandbox Code Playgroud)
Cir*_*四事件 23
助记符
cltq
是gas
英特尔的助记符,cdqe
如下所述:https://sourceware.org/binutils/docs/as/i386_002dMnemonics.html
助记符是:
cltq
):AT&T风格cdqe
):Intel术语:
这是GAS名称与英特尔版本非常不同的少数指令之一.as
接受助记符,但像NASM这样的英特尔语法汇编程序可能只接受英特尔名称.
影响
它符号将4个字节扩展为8个字节,在2的补码中意味着:
在C中,它通常表示从签名int
到的转换long
.
例:
mov $0123456700000001, %rax # eax=1, high bytes of rax=garbage
cltq
# %rax == $0000 0000 0000 0001
mov $-1, %eax # %rax = 0000 0000 FFFF FFFF
cltq
# %rax == $FFFF FFFF FFFF FFFF == qword $-1
Run Code Online (Sandbox Code Playgroud)
该指令仅在64位上可用.
另请考虑以下说明:
CWDE
(AT&T CWTL
),CBW
(AT&T CBTW
):较小的版本CDQE
,也以32位出现CQO
家庭,哪个标志延伸RAX
到RDX:RAX
MOVSX
家庭,这两个标志延伸和移动:movsbl指令做什么?带有断言的GitHub上的最小可运行示例:
C例子
GCC 4.9.3发出它:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
int i = strtol(argv[1], (char **)NULL, 16);;
long int l = i;
printf("%lx\n", l);
}
Run Code Online (Sandbox Code Playgroud)
编译和反汇编:
gcc -ggdb3 -std=c99 -O0 a.c
objdump -S a.out
Run Code Online (Sandbox Code Playgroud)
包含:
int main(int argc, char **argv) {
...
long int l2 = i;
400545: 8b 45 fc mov -0x4(%rbp),%eax
400548: 48 98 cltq
40054a: 48 89 45 f0 mov %rax,-0x10(%rbp)
Run Code Online (Sandbox Code Playgroud)
而且行为是:
$ ./a.out 0x80000000
ffffffff80000000
$ ./a.out 0x40000000
40000000
Run Code Online (Sandbox Code Playgroud)
jco*_*ctx 22
cltq将int提升为int64.shl 3,%rax对64位指针进行偏移(将rax中的任何内容乘以8).代码正在做的是循环遍历环境变量的指针列表.当它找到一个值为零时,那就是结束,它就会退出循环.
下面是Linux如何将环境变量存储在堆栈上方的RAM中.你会看到从0xbffff75c开始的指针; 指向0xbffff893,"TERM = rxvt".
jcomeau@intrepid:/tmp$ gdb test
GNU gdb (GDB) 7.2-debian
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /tmp/test...(no debugging symbols found)...done.
(gdb) break main
Breakpoint 1 at 0x80483e7
(gdb) run
Starting program: /tmp/test
Breakpoint 1, 0x080483e7 in main ()
(gdb) info reg
eax 0xbffff754 -1073744044
ecx 0xe88ed1c 243854620
edx 0x1 1
ebx 0xb7fc5ff4 -1208197132
esp 0xbffff6a8 0xbffff6a8
ebp 0xbffff6a8 0xbffff6a8
esi 0x0 0
edi 0x0 0
eip 0x80483e7 0x80483e7 <main+3>
eflags 0x200246 [ PF ZF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) x/160x 0xbffff6a8
0xbffff6a8: 0xbffff728 0xb7e86e46 0x00000001 0xbffff754
0xbffff6b8: 0xbffff75c 0xb7fe2940 0xb7ff7351 0xffffffff
0xbffff6c8: 0xb7ffeff4 0x08048254 0x00000001 0xbffff710
0xbffff6d8: 0xb7ff0976 0xb7fffac0 0xb7fe2c38 0xb7fc5ff4
0xbffff6e8: 0x00000000 0x00000000 0xbffff728 0x21b99b0c
0xbffff6f8: 0x0e88ed1c 0x00000000 0x00000000 0x00000000
0xbffff708: 0x00000001 0x08048330 0x00000000 0xb7ff64f0
0xbffff718: 0xb7e86d6b 0xb7ffeff4 0x00000001 0x08048330
0xbffff728: 0x00000000 0x08048351 0x080483e4 0x00000001
0xbffff738: 0xbffff754 0x08048440 0x08048430 0xb7ff12f0
0xbffff748: 0xbffff74c 0xb7fff908 0x00000001 0xbffff889
0xbffff758: 0x00000000 0xbffff893 0xbffff89d 0xbffff8ad
0xbffff768: 0xbffff8fd 0xbffff90c 0xbffff91c 0xbffff92d
0xbffff778: 0xbffff93a 0xbffff94d 0xbffff97a 0xbffffe6a
0xbffff788: 0xbffffe75 0xbffffef7 0xbfffff0e 0xbfffff1d
0xbffff798: 0xbfffff26 0xbfffff30 0xbfffff41 0xbfffff6a
0xbffff7a8: 0xbfffff73 0xbfffff8a 0xbfffff9d 0xbfffffa5
0xbffff7b8: 0xbfffffbc 0xbfffffcc 0xbfffffdf 0x00000000
0xbffff7c8: 0x00000020 0xffffe420 0x00000021 0xffffe000
0xbffff7d8: 0x00000010 0x078bfbff 0x00000006 0x00001000
0xbffff7e8: 0x00000011 0x00000064 0x00000003 0x08048034
0xbffff7f8: 0x00000004 0x00000020 0x00000005 0x00000008
0xbffff808: 0x00000007 0xb7fe3000 0x00000008 0x00000000
---Type <return> to continue, or q <return> to quit---
0xbffff818: 0x00000009 0x08048330 0x0000000b 0x000003e8
0xbffff828: 0x0000000c 0x000003e8 0x0000000d 0x000003e8
0xbffff838: 0x0000000e 0x000003e8 0x00000017 0x00000000
0xbffff848: 0x00000019 0xbffff86b 0x0000001f 0xbffffff2
0xbffff858: 0x0000000f 0xbffff87b 0x00000000 0x00000000
0xbffff868: 0x50000000 0x7d410985 0x1539ef2a 0x7a3f5e9a
0xbffff878: 0x6964fe17 0x00363836 0x00000000 0x00000000
0xbffff888: 0x6d742f00 0x65742f70 0x54007473 0x3d4d5245
0xbffff898: 0x74767872 0x45485300 0x2f3d4c4c 0x2f6e6962
0xbffff8a8: 0x68736162 0x47445800 0x5345535f 0x4e4f4953
0xbffff8b8: 0x4f4f435f 0x3d45494b 0x37303534 0x66656135
0xbffff8c8: 0x32353131 0x63346334 0x30393436 0x35386331
0xbffff8d8: 0x39346134 0x37316135 0x3033312d 0x31383339
0xbffff8e8: 0x2e303736 0x31303832 0x382d3033 0x33323731
0xbffff8f8: 0x39373936 0x53494800 0x5a495354 0x30313d45
0xbffff908: 0x00303030 0x48535548 0x49474f4c 0x41463d4e
0xbffff918: 0x0045534c 0x444e4957 0x4449574f 0x3833383d
(gdb) x/20s 0xbffff888
0xbffff888: ""
0xbffff889: "/tmp/test"
0xbffff893: "TERM=rxvt"
0xbffff89d: "SHELL=/bin/bash"
0xbffff8ad: "XDG_SESSION_COOKIE=45075aef11524c4c64901c854a495a17-1309381670.280130-817236979"
0xbffff8fd: "HISTSIZE=10000"
0xbffff90c: "HUSHLOGIN=FALSE"
0xbffff91c: "WINDOWID=8388614"
0xbffff92d: "USER=jcomeau"
0xbffff93a: "HISTFILESIZE=10000"
0xbffff94d: "LD_LIBRARY_PATH=/usr/src/jet/lib/x86/shared:"
0xbffff97a: "LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31"...
0xbffffa42: ":*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.d"...
0xbffffb0a: "eb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35"...
0xbffffbd2: ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=---Type <return> to continue, or q <return> to quit---
01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4"...
0xbffffc9a: "v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*."...
0xbffffd62: "yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;3"...
0xbffffe2a: "6:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:"
0xbffffe6a: "COLUMNS=80"
0xbffffe75: "PATH=/usr/src/jet/bin:/usr/local/bin:/usr/bin:/bin:/usr/games:/home/jcomeau:/home/jcomeau/bin:/home/jcomeau/src:/sbin:/usr/sbin:."
(gdb) quit
A debugging session is active.
Inferior 1 [process 10880] will be killed.
Quit anyway? (y or n) y
Run Code Online (Sandbox Code Playgroud)
您的编译器显然足够聪明,可以将简单格式化printf
为a puts
.提取环境字符串,以及i的后增量,就在代码中.如果你没有自己解决这些问题,你将永远不会理解它.只需"成为"计算机,然后逐步完成循环,使用我为gdb转储的数据,这一切都应该让你清楚.
小智 7
如果您的操作系统是64位,如果您没有声明函数驻留在另一个文件中,但您想在此文件中使用它.GCC默认认为此功能为32位.所以cltq只会使用低32位的RAX(返回值),高32位将填写1或0.希望这个网站能帮到你 http://www.mystone7.com/2012/05/23/cltq/
cltq
将EAX扩展到RAX.它是一种简短的形式movslq %eax, %rax
,可以节省代码字节.它的存在是因为x86-64从8086演变为386到AMD64.
它将EAX的符号位复制到更宽寄存器的所有高位,因为这是2的补码的工作原理.助记符是Convert Long to Quad的缩写.
AT&T语法(由GNU as
/ objdump
使用)使用与英特尔不同的助记符来获取某些指令(请参阅官方文档).您可以使用objdump -drwC -Mintel
或gcc -masm=intel -S
使用他们的指令参考手册的助记符英特尔和AMD的文件(见链接获得英特尔的语法x86的标签维基(有趣的事实:作为输入,气体可以接受记忆在任一模式).
machine mnemonics: MOVSX equivalent
code AT&T Intel AT&T Intel
66 98 cbtw cbw movsbw %al,%ax movsx ax,al
98 cwtl cwde movswl %ax,%eax movsx eax,ax
48 98 cltq cdqe movslq %eax,%rax movsxd rax,eax
Run Code Online (Sandbox Code Playgroud)
cltq
/ cdqe
显然只能在64位模式下使用,但其他两种模式在所有模式下均可用. movsx
和movzx
只用386引入,因此很容易/有效签署比/零扩展其它寄存器al
/ ax
或签署/零上,而载荷飞延伸.
想想cltq
/ cdqe
作为特殊情况的较短编码movslq %eax,%rax
.它的运行速度同样快.但唯一的好处是节省了几个字节的代码,因此使用它代替movsxd
/ 而牺牲其他任何东西都是不值得的 movzx
.
相关的指令组将 [e/r] ax的符号位复制到[e/r] dx的所有位中. 符号扩展eax
成edx:eax
是有用之前idiv
,或简单地在一个对寄存器的返回一个宽整数之前.
AT&T / Intel mnemonic effect
66 99 cwtd cwd word->doubleword dx = signbit(ax)
99 cltd cdq doubleword->quadword edx = signbit(eax)
48 99 cqto cqo quadword->octword rdx = signbit(rax)
Run Code Online (Sandbox Code Playgroud)
它们没有单指令等效,但您可以在两个指令中执行它们:例如mov %eax, %edx
/ sar $31, %edx
.
记住助记符
除了最初的8086之外,英特尔的助记符扩展到rax
最后.你可以记住这种情况,因为即使8086在一个寄存器中处理16位整数,也没有必要设置为符号位. 并阅读股息,而不是从.所以签到延伸到.e
cbw
dl
al
div r8
idiv r8
ax
dl:al
cbw
al
ax
AT&T助记符没有明显的暗示可以帮助你记住哪一个是哪一个.一些写的那些的*dx
结尾d
(为DX?),而不是通常l
的long
. cqto
打破这种模式,但八字是128b,因此必须是串联rdx:rax
.
IMO英特尔助记符更容易记住,而英特尔语法通常更容易阅读.(我首先学习了AT&T语法,但习惯了英特尔因为阅读英特尔/ AMD手册很有用!)
注意,对于零扩展,mov %edi,%edi
零扩展%edi
到%rdi
,因为对32位寄存器的任何写操作都会将高32位归零.(但在实践中,尝试mov
使用不同的寄存器(例如mov %eax, %ecx
),因为相同,同样会破坏Intel CPU中的mov-elimination.您经常会看到编译器生成的asm用于32位无符号args的函数使用a same,same
到零扩展,并且不幸的是,通常使用与src和destination相同的寄存器.
对于8或16到32(或隐含64),mov
工作以及and $0xff, %eax
.(或者更好的是,movzbl %al, %eax
所以mov-elimination可以使其在CPU上的零延迟$0xff
).
归档时间: |
|
查看次数: |
43538 次 |
最近记录: |