【第五节】Win32汇编程序设计
目录
一、汇编的第一个“helloworld”
二、汇编中的标号
三、@@的使用
四、数据定义
五、全局变量
六、局部变量
七、结构体
八、结构体的访问
九、获取变量地址
十、函数
十一、分支与循环
十二、内联汇编
十三、裸函数的使用
一、汇编的第一个“helloworld”
.386 ; 指定本工程应用的指令集为 80386
.model flat, stdcall ; 模式定义为平坦内存模式,调用模式为 stdcall
option casemap:none ; 选项设定为对大小写敏感include windows.inc ; 包含 Windows 头文件
include user32.inc ; 包含 user32 头文件
include kernel32.inc ; 包含 kernel32 头文件includelib user32.lib ; 包含 user32 库文件
includelib kernel32.lib ; 包含 kernel32 库文件.data ; 数据段
szCaption db 'Win32汇编', 0 ; 定义消息框标题字符串,以 0 结尾
szText db 'Hello World!', 0 ; 定义消息框内容字符串,以 0 结尾.code ; 代码段
start:invoke MessageBox, NULL, offset szText, offset szCaption, MB_OK ; 调用 MessageBox 函数显示消息框invoke ExitProcess, NULL ; 调用 ExitProcess 函数退出进程
end start
功能说明(代码注释用;)
-
invoke MessageBox, NULL, offset szText, offset szCaption, MB_OK
-
调用
MessageBox
函数显示一个消息框。 -
NULL
表示消息框没有所有者窗口。 -
offset szText
和offset szCaption
分别是消息框的内容和标题。 -
MB_OK
表示消息框只有一个 "OK" 按钮。
-
-
invoke ExitProcess, NULL
-
调用
ExitProcess
函数退出当前进程。 -
NULL
表示没有返回值。
-
这段代码的主要功能是显示一个带有 "Hello World!" 内容和 "Win32汇编" 标题的消息框,并在用户点击 "OK" 按钮后退出程序。
二、汇编中的标号
在汇编语言中,标号(Label)是一个非常重要的概念。标号本质上是一个符号,用于表示代码或数据的位置。通过使用标号,程序员可以更方便地引用和跳转到特定的代码段或数据段。
汇编语言中的标号规则:
1)允许使用字母、数字、下划线以及特殊符号@、$和?,但首字符不得为数字。
2)其长度限制在240个字符以内。
3)禁止使用指令名或其他保留关键字。
4)在同一作用域内,标号必须是唯一的。
### 标号的类型
1. **代码标号**:用于标记代码的位置,通常用于跳转指令(如 `JMP`、`CALL` 等)。
2. **数据标号**:用于标记数据的位置,通常用于数据定义指令(如 `DB`、`DW`、`DD` 等)。
### 代码标号
代码标号通常位于指令的前面,用于标记该指令的位置。例如:
start:mov ax, 42jmp start
在这个例子中,`start` 是一个代码标号,标记了 `mov ax, 42` 这条指令的位置。`jmp start` 指令会无条件跳转到 `start` 标号所在的位置。
### 数据标号
数据标号通常位于数据定义指令的前面,用于标记数据的位置。例如:
message db 'Hello, World!', 0
在这个例子中,`message` 是一个数据标号,标记了字符串 `'Hello, World!'` 的起始位置。程序可以通过 `message` 标号来访问这个字符串。
### 标号的用途
1. **跳转和调用**:通过标号,程序可以实现条件和无条件跳转,以及函数调用。
2. **数据访问**:通过标号,程序可以方便地访问数据段中的数据。
3. **模块化编程**:标号可以帮助组织代码,使其更具模块化和可读性。
### 示例
以下是一个简单的汇编程序,展示了代码标号和数据标号的使用:
.datamessage db 'Hello, World!', 0.code
start:mov ax, @datamov ds, axmov ah, 09hlea dx, messageint 21hmov ax, 4C00hint 21h
end start
在这个例子中:
- `message` 是一个数据标号,标记了字符串 `'Hello, World!'` 的起始位置。
- `start` 是一个代码标号,标记了程序的入口点。
通过这些标号,程序可以方便地访问数据和控制程序的执行流程。
三、@@的使用
在MASM中,@@提供了便捷的本地标号功能。
例如:
xor eax, eax
test eax, eax
je @F ; 跳转到此条指令后的第一个@@的地址
mov ebx, 99h
@@ ; 此条指令前的第一个@@的地址
loop @B ; 建议:在同一@@作用域下,@@、@F与@B之间不要间隔太远
通过使用@@、@F和@B,程序员可以更灵活地控制代码的跳转,尤其是在循环和条件判断中。
四、数据定义
常量定义:
const
IDD_DIALOG1 equ 101 ; 定义一个值为101的常量
数据定义:
data db "%02x", 0 ; 定义一个字符串FormatStr
未初始化数据定义:
hInstance dd ? ; 定义一个未初始化的变量
在汇编语言中,数据定义用于在数据段中分配内存并初始化数据。常量定义用于定义不可更改的值,数据定义用于定义已初始化的数据,而未初始化数据定义用于定义未初始化的变量。这些定义有助于组织和管理程序中的数据。
五、全局变量
格式:
变量名 类型 初始值1, 初始值2, ...
变量名 类型 重复数量 dup(初始值1, ...)
示例:
.data
wHour dw ? ; 2字节,未初始化
wMinute dw 10 ; 2字节,初始化为10
hWnd dd ? ; 4字节,未初始化
Buffer dw 100 dup(1, 2) ; 2 * 100字节,初始化为1和2的重复序列
szBuffer byte 1024 dup(?) ; 1024字节,未初始化
szText db 'Hello, world!', 0 ; 12字节,字符串
szHello db 'Hello,', 0dh, 0ah, 'world!', 0 ; 包含换行符的字符串
在汇编语言中,全局变量定义用于在数据段中分配内存并初始化数据。变量名后面跟着类型和初始值或重复数量及初始值。这些定义有助于组织和管理程序中的数据。
数据类型及表示方式:
六、局部变量
声明局部变量的关键字为 `LOCAL`,它会在栈中开辟出相应大小的空间用以保存这个局部变量。
例如:
LOCAL hDlgEdt : HWND ; 4字节空间
LOCAL dwNameSize : DWORD ; 4字节空间
LOCAL szName[128] : BYTE ; 128字节空间
在汇编语言中,局部变量通过 `LOCAL` 关键字声明,并在栈中分配内存。每个局部变量后面跟着类型和大小。这些定义有助于在函数或代码块中管理临时数据。
七、结构体
定义结构体:
WNDCLASS structStyle DWORD ?LpfnWndProc DWORD ?cbClsExtra DWORD ?
WNDCLASS ends
声明结构体:
data ?
stWndClass WNDCLASS <> ; 声明结构体
data
stWndClass WNDCLASS <1, 1, 1> ; 声明结构体并赋值
在汇编语言中,结构体用于定义复杂的数据结构。通过 `struct` 和 `ends` 关键字定义结构体,并在数据段中声明结构体变量。结构体变量可以不初始化,也可以在声明时进行初始化。这些定义有助于组织和管理复杂的数据结构。
八、结构体的访问
在MASM中访问结构体有三种方法:
1. **直接访问**:
mov eax, stWndClass.lpfnWndProc
2. **利用寄存器访问**:
mov esi, offset stWndClassmov eax, [esi + WNDCLASS.lpfnWndProc]
注意:第二句是 `[esi + WNDCLASS.lpfnWndProc]` 而不是 `[esi + stWndClass.lpfnWndProc]`。
3. **使用 `assume` 伪指令预先定义寄存器访问**:
mov esi, offset stWndClassassume esi: ptr WNDCLASSmov eax, [esi].lpfnWndProcassume esi: nothing
在汇编语言中,访问结构体成员可以通过直接访问、利用寄存器访问或使用 `assume` 伪指令预先定义寄存器访问。这些方法提供了灵活性和便利性,使得程序员可以根据具体需求选择最合适的方式来访问结构体成员。
九、获取变量地址
对于全局变量,它的地址在编译时已经由编译器确定,其用法如下:
mov 寄存器, offset 变量名
如果要在 `invoke` 伪指令的参数中用到一个局部变量的地址,该怎么办呢?参数中是不可能写入 `lea` 指令的,用 `offset` 也是不对的。MASM 对此有一个专用的伪操作符 `addr`,其格式为:
addr 局部变量名或全局变量名
注意:
mov eax, addr 局部变量名 ; 错误用法
假设在一个子程序中有如下 `invoke` 指令:
invoke Test, eax, addr szHello
其中 `Test` 是一个需要两个参数的子程序,`szHello` 是一个局部变量,会发生什么结果呢?编译器会把 `invoke` 伪指令和 `addr` 翻译成下面这个模样:
lea eax, [ebp-4]
push eax ; 参数2: addr szHello
push eax ; 参数1: eax
call Test
我们可以发现,在 `push` 第一个参数 `eax` 之前,`eax` 的值已经被 `lea eax, [ebp-4]` 指令覆盖了!
所以,当在 `invoke` 中使用 `addr` 伪操作符时,注意在它的前面不能用 `eax`,否则 `eax` 的值会被覆盖掉。当然,`eax` 在 `addr` 的后面的参数中用是可以的。幸亏 MASM 编译器对这种情况有如下错误提示:
error A2133: register value overwritten by INVOKE
这个错误提示提醒我们在使用 `addr` 伪操作符时要注意寄存器的使用顺序,避免不必要的问题。
十、函数
函数声明:
DlgProc proto :HWND, :UINT, :WPARAM, :LPARAM
函数定义:
FunName proc hDlg:HWND, dwVar:DWORDret
FunName endp
在汇编语言中,函数通过 `proto` 伪指令进行声明,并通过 `proc` 和 `endp` 关键字进行定义。函数声明指定了函数的名称和参数类型,而函数定义则包含了函数的具体实现。这些定义有助于组织和管理程序中的函数调用。
十一、分支与循环
在汇编语言中,分支和循环结构可以通过 `.if`、`.while`、`.break` 和 `.continue` 等伪指令来实现。
1. **条件分支**:
.if 表达式1表达式1为“真”要执行的指令.endif
当 `表达式1` 为真时,执行指定的指令。
2. **循环**:
.while 条件测试表达式指令[.break [.if 退出条件]][.continue].endw
当 `条件测试表达式` 为真时,执行循环体内的指令。可以使用 `.break` 和 `.if` 组合来提前退出循环,或者使用 `.continue` 跳过当前循环的剩余部分,直接进行下一次循环。
这些伪指令提供了类似于高级语言中的控制结构,使得汇编代码更具可读性和可维护性。
十二、内联汇编
在C/C++中,可以使用内联汇编来嵌入汇编代码。内联汇编有两种形式:块内联汇编和行内联汇编,二者可以交叉使用。
示例:
#define EXAMPLE_CODE asm
/* 内联汇编宏定义示例 */
EXAMPLE_CODE {pushadpopad
}
在定义一个具有多行汇编指令的宏时,一定要采取二者交叉使用的模式,否则会引起编译错误。块内联汇编使用 `asm { ... }` 的形式,而行内联汇编使用 `asm ...` 的形式。通过合理使用这两种形式,可以更灵活地在C/C++代码中嵌入汇编指令,从而实现更高效的代码执行。
十三、裸函数的使用
裸函数是一个没有任何可执行代码的空函数,它在内存中仅仅是一条地址信息。裸函数使用关键字 `__declspec(naked)` 定义,一个可运行的最简单的裸函数如下所示:
void __declspec(naked) TestFun()
{__asm ret
}
裸函数的特点是编译器不会为函数生成任何 prologue 或 epilogue 代码,这意味着函数体内必须手动编写所有的汇编代码,包括函数返回指令。裸函数通常用于需要精细控制函数执行流程的场合,例如编写中断处理程序或性能敏感的代码。
相关文章:

【第五节】Win32汇编程序设计
目录 一、汇编的第一个“helloworld” 二、汇编中的标号 三、的使用 四、数据定义 五、全局变量 六、局部变量 七、结构体 八、结构体的访问 九、获取变量地址 十、函数 十一、分支与循环 十二、内联汇编 十三、裸函数的使用 一、汇编的第一个“helloworld” .38…...

2.1算法的时间复杂度与空间复杂度
本篇博客介绍算法的时间复杂度与空间复杂度 一、算法效率 算法好坏从时间和空间两个维度衡量 二、时间复杂度 1.概念 时间复杂度是算法中基本操作的执行次数,定量描述了算法的运行时间 2.注意 (1)时间复杂度是偏…...

Linux VSFTP 部署与配置
一、VSFTP 简介与应用 VSFTP(Very Secure FTP Daemon)是一款功能强大、安全可靠的FTP服务器软件,广泛应用于Linux/Unix系统中。它提供了高效的文件传输服务,并具备诸多安全特性,如用户认证、权限控制、SSL/TLS加密等。…...

【Docker】Docker Consul
docker consul Docker Consul 是一个用于服务发现和配置的开源工具,它是 HashiCorp 公司推出的一个项目。Consul 提供了一个中心化的服务注册和发现系统,可以帮助开发人员轻松地在 Docker 容器和集群之间进行服务发现和配置管理。 Consul 使用基于 HTT…...

diamond安装与使用
1.前言 diamond是一款用于蛋白质和翻译后DNA搜索的序列比对工具,专为大规模序列数据的高性能分析设计。其主要特点包括: - 与BLAST相比,蛋白质和翻译后DNA的成对比对速度快100倍至10000倍。 2. 参考 https://github.com/bbuchfink/diamond …...

flume--数据从kafka到hdfs发生错误
解决: #1.将flume自带的依赖删除 mv /opt/installs/flume1.9/lib/guava-11.0.2.jar /opt/installs/flume1.9/lib/guava-11.0.2.jar.bak #2.将hadoop的依赖发送到flume下 cp /opt/installs/hadoop3.1.4/share/hadoop/common/lib/guava-27.0-jre.jar /opt/installs/f…...

Android笔试面试题AI答之Kotlin(14)
文章目录 64. Kotlin中定义函数还是属性场景?使用属性的场景使用函数的场景示例 65. 阐述Kotlin中变量初始化有几种?其中lateinit、by lazy、delegates.notNull有什么区别 ?Kotlin中变量初始化的几种方式lateinit、by lazy、Delegates.notNull的区别 66. Kotlin中…...

博弈论,CF 1600E - Array Game
目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1600E - Array Game 二、解题报告 1、思路分析 记最长递增前缀长度为L&a…...

win10安装docker,打包python、java然后centos执行镜像
一、win10安装Docker Desktop docker官网(需要魔法)下载:https://www.docker.com/products/docker-desktop/ 安装方法参考:https://blog.csdn.net/beautifulmemory/article/details/137970794 下载完毕后界面安装,不勾…...

【数据结构入门】二叉树之堆的实现
文章目录 前言一、树1.1 树的概念1.2 树的相关概念 二、二叉树2.1 二叉树的概念2.2 特殊的二叉树2.3 二叉树的性质 三、堆3.1 堆的概念3.2 堆的性质3.3 堆的存储3.4 堆的实现3.4.1 堆的初始化3.4.2 堆的销毁3.4.1 堆向上调整算法3.4.2 堆向下调整算法3.4.3 堆的创建3.4.4 堆的插…...

智能微气候:精准调控背后的算法革命
( 于景鑫 国家农业信息化工程技术研究中心)当人工智能遇见现代农业,会擦出怎样的火花?随着数字农业、智慧农业的蓬勃发展,人工智能技术正以前所未有的速度渗透到农业生产的方方面面。其中,以深度学习为代表的前沿算法,尤其是大语言模型(LLM),正在成为驱…...

eNSP 华为交换机链路聚合
华为交换机链路聚合 链路聚合好处: 1、提高带宽 2、链路冗余 SW_2: <Huawei>sys [Huawei]sys SW_2 [SW_2]vlan batch 10 20 [SW_2]int g0/0/4 [SW_2-GigabitEthernet0/0/4]port link-type access [SW_2-GigabitEthernet0/0/4]port default vl…...

编译器揭秘
从上世纪50年代开始,编程语言五花八门,编译器和解释器层出不穷。此处只列出常见编程语言的编译器和解释器信息,不常见的编程语言有单独文章介绍。 C/C cc 此处代表Unix C编译器,其他平台可能借用cc软链接到真正的C编译器。MSVC 微…...

ubuntu下qt连接mysql出现 QMYSQL driver not loaded
1、首先检查是否重新安装了MySQL的驱动,可以使用命令: sudo apt-get remove libqt5sql5-mysql sudo apt-get install libqt5sql5-mysql 2、重新安装ibmysqlclient-dev即可解决 sudo apt-get remove libmysqlclient-dev sudo apt-get install libmysq…...

html 首行缩进2字符
1. html 首行缩进2字符 1.1. 场景 在Html开发中让一段文字(富文本等)首行缩进两个文字,可能在前面加上8个“ ”,因为过去对CSS不熟悉,这种方法实现虽然比较直接,但是文字多的时候会有很多“ ”充斥在代码中…...

什么是IP?
目录 简介 IP IP协议 IP地址 发展历程 IP地址类型 公有地址 私有地址 IP地址编址方式 A类IP地址 B类IP地址 C类IP地址 D类IP地址 特殊的网址 子网 超网 无类间路由 IP地址的分配 IP地址管理 手工管理模式 DHCP分配IP地址的管理模式 通过交换机管理IP 地址…...

js拖拽交换元素位置
摘要:最近在做会议系统,9宫格小画面要支持拖拽调整顺序,需求已经实现了,简单记录下当时的逻辑处理。 /* 关于拖拽逻辑处理 start */ // 当前在拖动的下标 const curDragIndex useRef<number>(-1); /* 拖拽元素事件* onDragStart_开始* onDragend_结束 */ const handleD…...

在 C++ 中实现自定义容器的实用指南
在 C 中实现自定义容器的实用指南 在 C 编程中,容器是存储和管理数据的基本工具。标准库提供了多种容器,如 std::vector、std::list 和 std::map,但在某些情况下,开发者可能需要实现自定义容器以满足特定需求。本文将详细介绍如何…...

《深入浅出WPF》读书笔记.4名称空间详解
《深入浅出WPF》读书笔记.4名称空间详解 背景 主要讲明名称空间概念,可以理解为命名空间的引用。 xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml" 👆如x可以理解为一些列命名空间的引用。 不一一列举,只讲几个特殊的…...

电驱动总成
电驱动总成(Electric Drive Assembly)是电动汽车和混合动力汽车中关键的组成部分,主要负责将电能转化为机械能,以驱动汽车的轮胎。电驱动总成包括多个关键组件,通常可以分为以下几个主要部分: ### 主要组成…...

JavaScript class和正则
正则表达式练习 出生日期 年 月 日 ()表示一个整体 console.log(1909.match(^19\\d{2}$)); console.log(2024.match(^20(([01][0-9])|(2[0-4]))$)); //年 console.log(1909.match(^(19\\d{2})|(20(([01][0-9])|(2[0-4])))$)); // 月 console.log(12.match(^(0[1-9])|(1[0-2])…...

[Linux#42][线程] 锁的接口 | 原理 | 封装与运用 | 线程安全
互斥量 mutex • 大部分情况,线程使用的数据都是局部变量,变量的地址空间在线程栈空间 内,这种情况,变量归属单个线程,其他线程无法获得这种变量。 • 但有时候,很多变量都需要在线程间共享,这…...

奇异递归Template有啥奇的?
如果一个模版看起来很头痛,那么大概率这种模版是用来炫技,没啥用的,但是CRTP这个模版,虽然看起来头大,但是却经常被端上桌~ 奇异递归模板模式(Curiously Recurring Template Pattern, CRTP)是一…...

每天五分钟深度学习框架pytorch:神经网络工具箱nn的介绍
本文重点 我们前面一章学习了自动求导,这很有用,但是在实际使用中我们基本不会使用,因为这个技术过于底层,我们接下来将学习pytorch中的nn模块,它是构建于autograd之上的神经网络模块,也就是说我们使用pytorch封装好的神经网络层,它自动会具有求导的功能,也就是说这部…...

【办公软件】安全风险 Microsoft 已阻止宏运行,因为此文件的来源不受信任
Excel 2019版本,就出现安全风险 Microsoft 已阻止宏运行 因为此文件的来源不受信任的问题,宏直接就用不了了。 网上的解决方法,文件右键属性->取消安全锁。但存在没有安全锁这个选项。后查询到一个简单的解决方法。 打开Excel表格->文件…...

JavaScript语法基础之流程结构(顺序、选择、循环结构)
目录 1. 流程控制 1.1. 流程控制简介 1.1.1. 顺序结构 1.1.2. 选择结构 1.1.3. 循环结构 1.2. 选择结构:if 1.2.1. 单向选择:if… 1.2.2. 双向选择:if…else… 1.2.3. 多向选择:if…else_if…else… 1.3. 选择结构&#…...

集团数字化转型方案(四)
集团数字化转型方案通过全面部署人工智能(AI)、大数据分析、云计算和物联网(IoT)技术,创建了一个智能化的企业运营平台,涵盖从业务流程自动化、实时数据监控、精准决策支持,到个性化客户服务和高…...

【MySQL索引】索引失效场景
索引失效 1 全值匹配肯定不失效 2 最佳左前缀法则 索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。 3 主键插入顺序 页分裂,建议 让主键具有 AUTO_INCREMENT 4 计算、函数、类型转换(自动或手动)导致…...

基于MATLAB视觉的静态手势识别系统
一、课题介绍及思路 为了丰富手势识别方法的多样性,提高手势识别的正确率,提出了一种基于手势轮廓像素变化的手势识别方法。在Matlab环境下,设计并开发了一个基于视觉的静态手势识别系统。系统主要由两部分组成:手势分割与手势识…...

day02-作业题
一、简答题 请说出方法定义的全格式 访问修饰符 静态修饰符 返回值 方法名(参数列表){方法体;retrun 返回值;}请说出方法重载的概念 在一个类中,可以定义方法名相同,参数列表不相同(参数类型、参数个数或者参数顺序不同)的方法请简述什么是类…...