当前位置: 首页 > news >正文

【第五节】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 szTextoffset 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  ; 包含换行符的字符串

        在汇编语言中,全局变量定义用于在数据段中分配内存并初始化数据。变量名后面跟着类型和初始值或重复数量及初始值。这些定义有助于组织和管理程序中的数据。

数据类型及表示方式:

6342c19519fc4db19c8824c731563be9.jpeg

六、局部变量

        声明局部变量的关键字为 `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&#xff0e;概念 时间复杂度是算法中基本操作的执行次数&#xff0c;定量描述了算法的运行时间 2&#xff0e;注意 &#xff08;1&#xff09;时间复杂度是偏…...

Linux VSFTP 部署与配置

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

【Docker】Docker Consul

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

diamond安装与使用

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

flume--数据从kafka到hdfs发生错误

解决&#xff1a; #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有什么区别 &#xff1f;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官网&#xff08;需要魔法&#xff09;下载&#xff1a;https://www.docker.com/products/docker-desktop/ 安装方法参考&#xff1a;https://blog.csdn.net/beautifulmemory/article/details/137970794 下载完毕后界面安装&#xff0c;不勾…...

【数据结构入门】二叉树之堆的实现

文章目录 前言一、树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 堆的插…...

智能微气候:精准调控背后的算法革命

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

eNSP 华为交换机链路聚合

华为交换机链路聚合 链路聚合好处&#xff1a; 1、提高带宽 2、链路冗余 SW_2&#xff1a; <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年代开始&#xff0c;编程语言五花八门&#xff0c;编译器和解释器层出不穷。此处只列出常见编程语言的编译器和解释器信息&#xff0c;不常见的编程语言有单独文章介绍。 C/C cc 此处代表Unix C编译器&#xff0c;其他平台可能借用cc软链接到真正的C编译器。MSVC 微…...

ubuntu下qt连接mysql出现 QMYSQL driver not loaded

1、首先检查是否重新安装了MySQL的驱动&#xff0c;可以使用命令&#xff1a; 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开发中让一段文字&#xff08;富文本等&#xff09;首行缩进两个文字&#xff0c;可能在前面加上8个“ ”&#xff0c;因为过去对CSS不熟悉&#xff0c;这种方法实现虽然比较直接&#xff0c;但是文字多的时候会有很多“ ”充斥在代码中…...

什么是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 编程中&#xff0c;容器是存储和管理数据的基本工具。标准库提供了多种容器&#xff0c;如 std::vector、std::list 和 std::map&#xff0c;但在某些情况下&#xff0c;开发者可能需要实现自定义容器以满足特定需求。本文将详细介绍如何…...

《深入浅出WPF》读书笔记.4名称空间详解

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

电驱动总成

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

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...