文档章节

学 Win32 汇编[32] - 子程序进阶

涂孟超
 涂孟超
发布于 2014/09/26 15:35
字数 1170
阅读 7
收藏 0
点赞 0
评论 0

接: http://www.cnblogs.com/del/archive/2010/04/05/1704864.html

这是以前的一个求和函数的例子
; Test32_1.asm
.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

 
 
 
 
 

 

 

  

把上面的例子改为用寄存器传递参数:
; Test32_2.asm
.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 提前声明:
; Test32_3.asm
.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 是从左到右压栈参数.
; Test32_4.asm
.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 的下偏移? 因为是先压栈参数在调用函数.
; Test32_5.asm
.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 能更好地理解压参顺序:
; Test32_6.asm
.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 保护寄存器:
所谓保护就是在子过程执行前先压栈, 执行后在出栈.
; Test32_7.asm
.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 来得简洁:
; Test32_8.asm
.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 都可以代替了.

该学模块化编程了.

本文转载自:http://www.cnblogs.com/del/archive/2010/04/26/1721193.html

共有 人打赏支持
涂孟超
粉丝 12
博文 2004
码字总数 14107
作品 0
深圳
程序员
Win32汇编语言核心

一. Win32汇编源程序的结构 hello world程序 .386 .model flat, stdcall option casemap: none include windows.inc include user32.inc includelib user32.lib include kernel32.inc inclu......

呼噜呼噜睡翻天 ⋅ 2014/04/02 ⋅ 0

win32汇编和x64汇编?

win32汇编升到winx64汇编,转型容易吗?我指的是会win32汇编,还学x64汇编吗?我是初学,能不能直接学x64汇编语言,请推荐本书?

IIOWE ⋅ 2014/10/01 ⋅ 3

为什么破解要学win32汇编?

听说破解要学win32汇编,写壳也要用win32汇编?为什么呢?不学不能学破解吗?

IIOWE ⋅ 2014/10/02 ⋅ 13

Win32汇编开发环境介绍和RadAsm简明教程

Win32汇编开发环境介绍和RadAsm简明教程 现在很多朋友都在学习汇编语言,一方面汇编语言是大学计算机课程的必修课,另一方面则是为了从其它语言转到汇编语言来,无论什么原因,我认为学习汇编...

nothingfinal ⋅ 2009/08/01 ⋅ 0

[Beautifulzzzz的博客目录] 快速索引点这儿O(∩_∩)O~~,红色标记的是不错的(⊙o⊙)哦~

3D相关开发 [direct-X] 1、direct-X最小框架 [OpenGL] 1、环境搭建及最小系统 [OpenGL] 2、企业版VC6.0自带的Win32-OpenGL工程浅析 51单片机 [51单片机] 1602液晶显示控制代码 [51单片机] 1...

史迪奇2号 ⋅ 2017/08/01 ⋅ 0

MASM32 SDK

MASM32 SDK是不同工具软件的大集合,它的汇编编译器用的是微软MASM软件包中的Ml.exe,资源编译器和32位链接器使用的是Microsoft Visual Studio中的Rc.exe和Link.exe,同时包含了Microsoft V...

匿名 ⋅ 2011/05/04 ⋅ 1

从Native到Web, NaCl学习笔记(二): 技术限制&Win32移植过程

一些限制相对于Win32来说, NaCl相当于另一个平台, 一些操作系统相关的API需要移植. 除此之外, 参考Technical Overview, 还有一些其它的限制: 不支持硬件异常 不支持创建进程 不支持传统的TCP...

长平狐 ⋅ 2012/11/12 ⋅ 0

汇编器--Yasm

Yasm是一个完全重写的NASM汇编。目前,它支持x86和AMD64指令集,接受NASM和气体汇编语法,产出二进制, ELF32 , ELF64 , COFF , Mach - O的( 32和64 ) , RDOFF2 ,的Win32和Win64对象的...

匿名 ⋅ 2009/04/11 ⋅ 1

王小波的计算机水平到底有多好?

原文出处:知乎 导读:有网友在知乎上提问: 王小波的计算机水平到底有多好,在王小波自己的小说中,王小波非常骄傲地说,写书的软件都是自己编写的,王小波是自学的还是教的?都会什么语言?...

知乎 ⋅ 2017/05/05 ⋅ 0

计算机图形/图像(GPU/OpenGL)

> OpenGL ES 《OpenGL ES应用开发实践指南 -Android卷》-https://download.csdn.net/download/donkor/9931418 《计算机图形学(openGL版)第三版(中文版)》 矩阵变换:《线性代数》和《3D 数学...

shareus ⋅ 04/25 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

容器之重命名镜像

使用docker tag命令来重命名镜像名称,先执行help,查看如何使用如下 mjduan@mjduandeMacBook-Pro:~/Docker % docker tag --helpUsage:docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TA...

汉斯-冯-拉特 ⋅ 7分钟前 ⋅ 0

with 的高级用法

那么 上下文管理器 又是什么呢? 上下文管理器协议包含 __enter__ 和 __exit__ 两个方法。with 语句开始运行时,会在上下文管理器对象上调用 __enter__ 方法。with 语句运行结束后,会在上下...

阿豪boy ⋅ 27分钟前 ⋅ 0

使用 jsoup 模拟登录 urp 教务系统

需要的 jsoup 相关 jar包:https://www.lanzous.com/i1abckj 1、首先打开教务系统的登录页面,F12 开启浏览器调试,注意一下 Request Headers 一栏的 Cookie 选项,我们一会需要拿这个 Cook...

大灰狼时间 ⋅ 27分钟前 ⋅ 0

关于线程的创建

转自自己的笔记: http://note.youdao.com/noteshare?id=87584d4874acdeaf4aa027bdc9cb7324&sub=B49E8956E145476191C3FD1E4AB40DFA 1.创建线程的方法 Java使用Thread类代表线程,所有的线程对......

MarinJ_Shao ⋅ 38分钟前 ⋅ 0

工厂模式学习

1. 参考资料 工厂模式-伯乐在线 三种工厂-思否 深入理解工厂模式 2. 知识点理解 2.1 java三种工厂 简单工厂 工厂模式 抽象工厂 2.2 异同点 逐级复杂 简单工厂通过构造时传入的标识来生产产品...

liuyan_lc ⋅ 50分钟前 ⋅ 0

Java NIO

1.目录 Java IO的历史 Java NIO之Channel Java NIO之Buffer Java NIO之Selector Java NIO之文件处理 Java NIO之Charset Java 可扩展IO 2.简介 “IO的历史”讲述了Java IO API从开始到现在的发...

士别三日 ⋅ 54分钟前 ⋅ 0

[Err] ORA-24344: success with compilation error

从txt文本复制出创建function的脚本,直接执行,然后报错:[Err] ORA-24344: success with compilation error。 突然发现脚本的关键字,居然不是高亮显示。 然后我把脚本前面的空格去掉,执行...

wenzhizhon ⋅ 今天 ⋅ 0

Spring Security授权过程

前言 本文是接上一章Spring Security认证过程进一步分析Spring Security用户名密码登录授权是如何实现得; 类图 调试过程 使用debug方式启动https://github.com/longfeizheng/logback该项目,...

hutaishi ⋅ 今天 ⋅ 0

HAProxy基于KeepAlived实现Web高可用及动静分离

前言 软件负载均衡一般通过两种方式来实现: 基于操作系统的软负载实现 基于第三方应用的软负载实现 LVS是基于Linux操作系统实现的一种软负载,而HAProxy则是基于第三方应用实现的软负载。 ...

寰宇01 ⋅ 今天 ⋅ 0

微软自研处理器的小动作:已经开始移植其他平台的工具链

微软将 Windows 10 、Linux 以及工具链如 C/C++ 和 .NET Core 运行时库、Visual C++ 2017 命令行工具、RyuJIT 编辑器等移植到其自主研发的处理器架构 E2。微软还移植了广泛使用的 LLVM C/C++...

linux-tao ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部