关于函数调用约定 :函数调用约定

这是以前的一个求和函数的例子
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.code
sum proc v1:dword, v2:dword, v3:dword
    mov eax, v1
    add eax, v2
    add eax, v3
    ret
sum endp
;
main proc
    invoke sum, 11, 22, 33
    PrintDec eax; 66
    ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
把上面的例子改为用寄存器传递参数:
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.code
sum proc
    add eax, ecx
    add eax, edx
    ret
sum endp
;
main proc
    mov eax, 11
    mov ecx, 22
    mov edx, 33
    invoke sum
    PrintDec eax; 66
    ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
如果调用的函数在之后实现, 须用 PROTO 提前声明:
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

;sum proto v1:dword, v2:dword, v3:dword
sum proto :dword, :dword, :dword ;函数声明的主要是参数类型, 一般省略参数名

.code
main proc
    invoke sum, 11, 22, 33 ;现在调用的是之后的函数
    PrintDec eax; 66
    ret
main endp
;
sum proc v1, v2, v3
    mov eax, v1
    add eax, v2
    add eax, v3
    ret
sum endp
end main
----------------------------------------------------------------------------------------------------------------
测试 StdCall 模式下的参数压栈顺序:
----------------------------------------------------------------------------------------------------------------
 子程序可以指定语言模式(StaCall、C、SysCall、Basic、Fortran、Pascal);
如果不指定则默认使用在 .model 中指定的语言模式.

StaCall、C、SysCall 是从右到左压栈参数;
Basic、Fortran、Pascal 是从左到右压栈参数.
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.code
sum proc stdcall v1, v2, v3
    ;查看参数压栈顺序(StdCall 是从右到左 push)
    mov edx, [ebp+16]
    PrintHex edx      ;33
   
    mov edx, [ebp+12]
    PrintHex edx      ;22
   
    mov edx, [ebp+8]
    PrintHex edx      ;11
   
    PrintLine
   
    ;下面求和代码
    mov eax, v1
    add eax, v2
    add eax, v3
    ret
sum endp
;
main proc
    invoke sum, 11h, 22h, 33h
    PrintDec eax; 66
    ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
测试 Pascal 模式下的参数压栈顺序:
----------------------------------------------------------------------------------------------------------------
这是和上面的对比练习, 它们的压栈参数的顺序是反的.
其中的 EBX+8 是最后压栈参数(DWORD)的地址, 同样 EBX 向上偏移 12、16 就分别是另外两个参数的地址.
地址 EBX+4 是 RET 将要返回的地址.
为什么参数不是在 EBX 的下偏移? 因为是先压栈参数在调用函数.
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.code
sum proc pascal v1, v2, v3
    ;查看参数压栈顺序(pascal 是从左到右 push)
    mov edx, [ebp+16]
    PrintHex edx      ;11
   
    mov edx, [ebp+12]
    PrintHex edx      ;22
   
    mov edx, [ebp+8]
    PrintHex edx      ;33
   
    PrintLine
   
    ;下面求和代码
    mov eax, v1
    add eax, v2
    add eax, v3
    ret
sum endp
;
main proc
    invoke sum, 11h, 22h, 33h
    PrintDec eax; 66
    ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
如果用 Call 代替 invoke 能更好地理解压参顺序:
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.code
ViewParam proc C v1, v2, v3 ;把这里的 C 换为 pascal 会有完全不同的结果
    PrintDec v1 ;11
    PrintDec v2 ;22
    PrintDec v3 ;33
    ret
ViewParam endp
;
main proc
    push 33
    push 22
    push 11
    call ViewParam
    leave ;leave 是上面几个 push 的反操作, 省了不少 pop
    ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
子过程使用 uses 保护寄存器:
----------------------------------------------------------------------------------------------------------------
 所谓保护就是在子过程执行前先压栈, 执行后在出栈.
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.data
    dwVal dd ?
.code
sum proc stdcall uses eax ecx edx, v1, v2, v3 ;这其中的 stdcall 可省略
    mov eax, v1
    mov ecx, v2
    mov edx, v3
    add eax, ecx
    add eax, edx
    mov dwVal, eax
    ret
sum endp
;
main proc
    ;sum 对这三个寄存器进行的保护, 先给些测试值
    mov eax, 7
    mov ecx, 8
    mov edx, 9
   
    invoke sum, 11, 22, 33
    PrintDec dwVal ;66
   
    PrintDec eax ;7
    PrintDec ecx ;8
    PrintDec edx ;9
    ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
使用 uses 不如使用 pushad 和 popad 来得简洁:
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.data
    dwVal dd ?
.code
sum proc v1, v2, v3
    pushad
    mov eax, v1
    mov ecx, v2
    mov edx, v3
    add eax, ecx
    add eax, edx
    mov dwVal, eax
    popad
    ret
sum endp
;
main proc
    mov eax, 7
    mov ecx, 8
    mov edx, 9
   
    invoke sum, 11, 22, 33
    PrintDec dwVal ;66
   
    PrintDec eax ;7
    PrintDec ecx ;8
    PrintDec edx ;9
    ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
和子程序密切相关的有两个指令: call 和 ret
call 相当于 push+jmp;
ret 相当于 pop+jmp;
有些 ret 后面还有个数字, 如 ret 8, 这相当于 ret 后再 esp+8(这是清理 8 字节的堆栈).

另外程序可以同 public 和 private 指定是否能跨模块使用, 默认是 public, 极少用到 private.

声明其他模块成员的 extrn、extern、public 关键字, 现在用 proto 都可以代替了.

Win32ASM学习[20]:子程序相关推荐

  1. 10以内数的组成分解图_学前儿童如何学习20以内的加减法,收藏了

    学前儿童如何学习20以内的加减法,收藏了 20以内的数的分成及加减法,是幼儿对数与量的基本认识.是幼儿园教材中的学习内容.如何教好"20以内的加法"呢?我在这里谈几点学习20以内的 ...

  2. 深度学习-20:神经科学、脑科学和稀疏特性

    深度学习-20:神经科学.脑科学和稀疏特性 深度学习原理与实践(开源图书)-总目录,建议收藏,告别碎片阅读! 第二次世界大战之后,美苏在全维度展开了霸权竞赛,人工智能研究伴随着计算机的发展也开始进入佳 ...

  3. STC15F104W无线收发模块,源程序注释很详细,PDF格式说明书,可以学习20个遥控器,3个按键一个学习按键还有按键开和按键关

    STC15F104W无线收发模块,源程序注释很详细,PDF格式说明书,可以学习20个遥控器,3个按键一个学习按键还有按键开和按键关,遥控器也能控制开关,用充电宝或手机充电器供电都行,频率433和315 ...

  4. for循环10000次花多长时间_我的三菱FX PLC学习之子程序调用与循环

    戳上方蓝字 "技成电工课堂" 关注我们哦! 上次,我们学习了程序流程转移中的条件跳转CJ,这次,我们接着向子程序调用CALL和FOR循环发起进攻吧! 显然,子程序调用CALL和FO ...

  5. Win32ASM学习[21]:宏汇编(1)

    ---------------------------------------------------------------------------------------------------- ...

  6. 【机器学习】深度学习20个笔试题

    请不要在题上写画答案,写在答题纸上 假设你训练SVM后,得到一个线性决策边界,你认为该模型欠拟合.在下次迭代训练模型时,应该考虑: A.增加训练数据 B.减少训练数据 C.计算更多变量 D.减少特征 ...

  7. 深度学习(20):nerf论文翻译与学习

    目录 1 Introduction 2 Related Work 3 Neural Radiance Field Scene Representation 4 Volume Rendering wit ...

  8. Javascript基础学习20问(二)

    1.函数(方法):封装执行一项专门任务的步骤的代码序列-->重用 2.参数:方法内独有的变量,接受传入数据,在方法中处理 3.作用域:一个变量的可用范围     全局作用域:全局变量     局 ...

  9. Win32ASM学习[12]:位测试指令位扫描指令

    ---------------------------------------------------------------------------------------------------- ...

最新文章

  1. Android Studio导入Eclipse项目的两种方法
  2. H.265的NALU
  3. ExtJs中column与form布局的再次领悟
  4. 使用舵机PWM信号控制直流电机的转动
  5. android 屏幕录像
  6. CV之FDFA:利用MTCNN的脚本实现对LFW数据集进行FD人脸检测和FA人脸校准
  7. 统计通话次数和时间的软件_通话时间统计app下载|通话时间统计安卓版下载 v1.0.3 - 跑跑车安卓网...
  8. 23 WM配置-策略-入库策略3-定义现有库存的附加策略I(Addition to Existing Stock Strategy)
  9. 2021亳州高考成绩查询,2021年亳州高考状元名单公布,亳州文理科状元是谁多少分...
  10. View与Model绑定注意事项 (视图无数据显示)
  11. 基于源码编译安装openssh
  12. mysql字段长度的作用_数据库字段的长度 作用
  13. python3出现TypeError: can only concatenate str (not bytes) to str的错误,大一刚上手python的学习,望大神解决。感激不尽
  14. 工业电脑量产测试之----U盘DOS 启动盘制作(1)
  15. 掠食细菌—蛭弧菌B. bacteriovorus,可以对抗革兰氏阴性感染?
  16. [附源码]java毕业设计基于的高校学生考勤管理系统
  17. 微软同步备份工具SyncToy,值得使用
  18. Note: LSR LER
  19. Testin云测技术沙龙在沪召开,云监控预警成关注重点
  20. view \function\行转列的方法。

热门文章

  1. html网页制作图案,巧用CSS滤镜做图案文字-网页设计,HTML/CSS
  2. java 本地方法栈_Java虚拟机栈和本地方法栈
  3. 51cto 检测ip地址冲突_在Linux中发现IP地址冲突的方法
  4. 计算机仿真在机械应用,浅谈计算机仿真在机械的应用.doc
  5. React Native项目自动化打包发布
  6. HashSet源码分析:JDK源码系列
  7. Shadow DOM及自定义标签
  8. JavaScript高级特征之面向对象笔记
  9. 在Windows运行Python程序
  10. class-感知机Perception