x86汇编学习笔记(二)

x86汇编学习笔记(二)

Zhiyu Lv4

1 win32的汇编开发流程

2 win32汇编源程序的结构

Hello world程序在DOS汇编:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
;堆栈段
stack segment stack
db 100 dup (?)
stack ends

;数据段
data segment
szHello db 'Hello, world',0dh,0ah,'$'
data ends

;代码段
code segment
assume cs:code,ds:data,ss:stack
start:
mov ax,data
mov ds,ax

mov ah,9
mov dx,offset,szHello
int 21h
code ends
end start

Hello world的Win32程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
        .386
.model flat,stdcall
option casemap:none
;include定义
include windows.inc
include user32.inc
include user32.lib
include kernel32.inc
include kernel32.lib

;数据段
.data
szCaption db 'A MessageBox',0
szText db 'Hello, world',0

;代码段
.code
start:
invoke MessageBox, NULL, offset szText, offset szCaption, MB_OK
invoke ExitProcess, NULL

end start

2.1 模式定义

2.1.1 指定使用的指令集

.386是汇编的伪指令,用于告诉编译器在本程序中使用的指令集为80386所拥有的指令集。类似的指令还有:.8086, .186, .386p, .486/486p, .586/.586p等。后面带p的伪指令表示程序中可以使用特权指令(必须在特权级0上运行的指令)如:mov cr0, eax

2.1.2 .model语句

用来定义程序工作的模式。用法如下:

.model 内存模式 [, 语言模式] [, 其他模式]

模式 内存使用方式
tiny 用来建立 .com文件,所有代码、数据和堆栈都在同一个64KB段内
small 建立代码和数据分别别用一个64KB段的 .exe文件
medium 代码段可以有多个64KB段,数据段只有一个64KB段
compact 代码段只有一个64KB段,数据段可以有多个64KB段
large 代码段和数据段都可以由多个64KB段
huge 同large,并且数据段中的一个数组也可以超过64KB
flat Win32程序使用的模式,代码和数据段使用同一个4GB段

对于运行在保护模式下的win32程序,它只有一种内存模式——flat模式,即每一个应用程序都拥有其相互独立的4GB地址空间。

2.1.3 option语句

option casemap:none,该语句定义了程序中变量和子程序名是否对大小写敏感。由于Win32 API名称是区分大小写的,故在win32汇编程序中必须指定此语句

2.2 段的定义

2.2.1 段的概念

一个包含全部段的源程序结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.386
.model flat, stdcall
option casemap:none
<include statements>

.stack [堆栈段的大小]
.data
<一些初始化过的变量定义>
.data?
<一些没有初始化过的变量定义>
.const
<一些常量定义>
.code
<代码>
<开始标号>
<语句>
end 开始标号
  • 其中.stack, .data, .data?, .const和.code都是分段伪指令。
  • Win32只有代码和数据段之分,因此.data, .data?和.const属于数据段,.code属于代码段。
  • 与DOS汇编不同,Win32汇编不必考虑堆栈,.stack段定义常常被忽略。

2.2.2 数据段

.data,.data?和.const定义在数据段,分别对应不同方式的数据定义,在最后生成的可执行文件中也放置在不同的节区(Section)。程序中的数据定义一般可以归纳为三类:

  1. 可读可写的已定义变量。被定义在.data段,具有以下性质:
    • 在源程序已经被定义了初始值。
    • 具有可读可写性。
    • 在程序装入完成之后,这些值存在于内存中。
    • .data段一般存放在可执行文件的_DATA节区内。
  2. 可读可写的未定义变量。可定义在.data段,也可以定义在.data?段,具有以下性质:
    • 一般用作缓冲区,或者程序执行后在开始使用。
    • 若定义在.data段,则编译器在生成可执行文件时会保留声明大小的空间,即使它们是全0
    • 若定义在.data?段,则编译器在生成可执行文件时只会记录空间大小信息,不会浪费磁盘空间,而是在程序执行时才会用到。
    • .data?段在可执行文件中一般放在_BSS节区。
  3. 常量。如一些要显示的字符串信息。
    • 它们在程序装入时就已经有效,但在整个执行过程中不需要修改。
    • 具有可读不可写性。
    • 如果程序对.const段进行写操作,会引起保护错误并结束程序。

2.2.3 代码段

  • .code段时代码段,所有的指令都必须写在代码段中
  • 在可执行文件中,代码段一般放在_TEXT节区。
  • Win32环境下的数据段是不可执行的,只有代码段有可执行的属性。(特权级0下运行的程序对所有段有读写权限)

2.2.4 堆栈段

  • Win32程序中不必定义堆栈段,系统会自动分配堆栈空间。
  • 堆栈段的内存属性是可读写并可执行的。(靠动态修改代码的反跟踪模块可以拷贝到堆栈中边修改边执行)

2.3 程序入口与结束

  • 汇编源程序中,并没有main函数来指定开始执行的地方。取而代之的是程序的最后一句的end语句end [开始地址]
  • 上述语句的开始地址就是源程序从代码段开始执行的地址。
  • 上述语句同时还表示源程序结束,所有代码都必须在end语句之前。
  • 多模块程序编写时,单一的模块可以没有入口标号,但是最后把多个模块连接在一起时,必须有一个主模块的入口地址被指明。

3 API的调用

3.1 API是什么

3.2 如何调用

3.3.1 invoke语句

3.3.2 函数的声明与返回值

3.3.3 include语句

  • Title: x86汇编学习笔记(二)
  • Author: Zhiyu
  • Created at : 2019-09-30 15:52:59
  • Updated at : 2026-02-18 00:46:12
  • Link: https://qgrain.github.io/2019/09/30/x86汇编学习笔记-二/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments