找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 7313|回复: 12

【汇编】x64下的汇编与VS

[复制链接]
发表于 2015-7-24 04:01:31 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
1、寄存器
通用寄存器:
8位al/ahcl/chdl/dhbl/bhsplbplsildilr8br9br10br11br12br13br14br15b
16位axcxdxbxspbpsidir8wr9wr10wr11wr12wr13wr14wr15w
32位eaxecxedxebxespebpesiedir8dr9dr10dr11dr12dr13dr14dr15d
64位raxrcxrdxrbxrsprbprsirdir8r9r10r11r12r13r14r15

64位媒介、浮点寄存器
mmx0/fpr0
mmx1/fpr1
mmx2/fpr2
mmx3/fpr3
mmx4/fpr4
mmx5/fpr5
mmx6/fpr6
mmx7/fpr7

标识寄存器
16位32位64位
flagseflagsrflags

指令指针寄存器
16位32位64位
ipeiprip

128位媒介寄存器
xmm0
xmm1
xmm2
xmm3
xmm4
xmm5
xmm6
xmm7
xmm8
xmm9
xmm10
xmm11
xmm12
xmm13
xmm14
xmm15


注:al为ax的低8位,ah为ax的高8位,相同的还有cx(cl低,ch高)、dx(dl低,dh高)、bx(bl低,bh高)。spl、bpl、sil、dil分别为sp、bp、si、di的低8位。r8b-r15b分别为r8w-r15w的低8位。

2、调用约定
这里所说的调用约定,是Windows API的调用约定,以及VS编译的x64平台C语言程序中函数的调用约定。
规则如下:
  • 前四个参数用rcx、rdx、r8、r9存储,但是同时也要留出栈空间。剩下的参数均通过栈传参。
  • 调用者维护栈,被调用者返回的时候只需要ret就行了。


来解释一下其中的规则。首先就是参数传递的规则。来用MessageBox举例。

首先如果你链接了x64平台的user32.lib,那么你的整个程序之中就会有__imp_MessageBoxA这个符号,它是个函数指针,指向user32.dll中的MessageBoxA函数的入口。
范例代码(NASM编译通过):
  1. %define MB_OK 0

  2. segment .text
  3. start:
  4. sub rsp,0x28
  5. mov r9,MB_OK
  6. mov r8,g_szTitle
  7. mov rdx,g_szPrompt
  8. xor rcx,rcx
  9. call [__imp_MessageBoxA]
  10. add rsp,0x28
  11. ret

  12. segment .data
  13. g_szTitle db "x64汇编",0
  14. g_szPrompt db "Hello World!",0
复制代码
其中我们要调用的函数是MessageBoxA,它有四个参数:窗口句柄,提示文本,标题栏文本,样式。
四个参数,每个参数8字节对齐,所有参数总字节数又是16字节对齐的,因此我们需要预留出0x20个字节的栈空间。然后我们还要再留出8个字节用于和call指令压入的返回地址值拼成16字节对齐。
因此预留的栈大小为:8 + 16字节对齐(要调用的函数的参数个数×8)
为什么要预留栈空间?因为,当你使用寄存器传参数的时候,你会发现有时候这个寄存器有时要被用于其它用途(比如调用别的函数、用作数学运算等),但是你又不想丢失寄存器之前存储的数值。因此,你可以把寄存器存储的数值暂存到栈上的预留空间里,以便于后续的读取。
调用者不必帮被调用者存储参数的值——调用者只需要分配好栈空间然后把前四个参数用rcx、rdx、r8、r9来传递(剩下的参数则通过栈传递)。被调用者自己决定是否将参数存储到栈上。
此外,编写x64汇编时,要注意一点:尽可能不要重复使用push和pop,因为这样会降低性能。其中,x64的push如果是要压入立即数的话,可能会产生一个字节数很多的指令,CPU从内存中读取指令是需要时间的。另外就是,push、pop需要做两个操作,先改变rsp的值,然后将数据存入栈顶,这个过程需要消耗额外的CPU时钟周期。而一次性将栈内存分配好,然后用mov来穿参的话,会比使用连续的push和pop快很多。

回复

使用道具 举报

发表于 2015-7-24 07:25:24 | 显示全部楼层
啥时候  A5老板 搞一个 x64 下面的 内联汇编帖子 玩玩呗?
回复 赞! 靠!

使用道具 举报

发表于 2015-7-24 08:24:49 | 显示全部楼层
调用约定讲的很详细吖
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2015-7-24 16:14:33 | 显示全部楼层
NiuDeHua 发表于 2015-7-24 07:25
啥时候  A5老板 搞一个 x64 下面的 内联汇编帖子 玩玩呗?

内联汇编懒得搞。外联的抽空做一个给你玩玩
回复 赞! 靠!

使用道具 举报

发表于 2015-7-29 07:09:49 | 显示全部楼层
0xAA55 发表于 2015-7-24 16:14
内联汇编懒得搞。外联的抽空做一个给你玩玩

只要能“联” 就ok 的,  坐等新帖出世、
回复 赞! 靠!

使用道具 举报

发表于 2018-1-14 16:07:03 | 显示全部楼层
可以可以!!
回复

使用道具 举报

发表于 2020-1-30 18:28:28 | 显示全部楼层
支持楼主!今天被调用约定搞惨了, 靠着win32asm记忆淌水x64,结果BSoD了一下午
回复 赞! 靠!

使用道具 举报

发表于 2020-1-30 18:35:29 | 显示全部楼层
0xAA55 发表于 2015-7-24 16:14
内联汇编懒得搞。外联的抽空做一个给你玩玩

外联怎么联,也给俺玩玩呗
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2020-2-1 01:38:36 | 显示全部楼层
watermelon 发表于 2020-1-30 18:35
外联怎么联,也给俺玩玩呗

用nasm之类的工具写汇编,编译为“-f win64”格式的obj,然后丢给VS的链接器LINK和vs的其它.c、.cpp的obj一起链接就可以了。

不过,vs的.c和.cpp有“全程序优化”,可以跨obj实现函数内联,而你用汇编器单独写的汇编函数,不会被“全程序优化”实现函数内联。
回复 赞! 靠!

使用道具 举报

发表于 2020-2-1 01:59:10 | 显示全部楼层
0xAA55 发表于 2020-2-1 01:38
用nasm之类的工具写汇编,编译为“-f win64”格式的obj,然后丢给VS的链接器LINK和vs的其它.c、.cpp的obj ...

64位下用需要使用汇编的地方已经非常少了 一少部分外联足够了
回复 赞! 靠!

使用道具 举报

发表于 2020-2-1 13:15:34 | 显示全部楼层
0xAA55 发表于 2020-2-1 01:38
用nasm之类的工具写汇编,编译为“-f win64”格式的obj,然后丢给VS的链接器LINK和vs的其它.c、.cpp的obj ...

哦,这样的就也是用了汇编语言的文件,所以算“外联”
回复 赞! 靠!

使用道具 举报

发表于 2020-2-1 14:32:43 | 显示全部楼层
话说xor rcx, rcx这样的清零运算操作会被vs的汇编编译器优化成xor ecx,ecx因为对32位寄存器的写操作和运算操作会对高32位清零,而后者的opcode又比前者短,所以编译器更喜欢。
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2020-2-2 19:58:04 | 显示全部楼层
watermelon 发表于 2020-2-1 14:32
话说xor rcx, rcx这样的清零运算操作会被vs的汇编编译器优化成xor ecx,ecx因为对32位寄存器的写操作和运算 ...

nasm也有这样的优化效果,但可以关闭
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-22 12:44 , Processed in 0.039725 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表