采用NASM汇编器进行Win32汇编(一)

NASM(Netwide Assembler)是一款设计用于80x86与x86-64架构的汇编器(assembler),其具有较好的可移植性(portability)并支持模块化(modularity)。NAMS支持多种目标文件(object file)格式,包括Linux和*BSD的a.out、ELF、Mach-O、16-bit和32-bit的.obj(OMF)格式,以及COFF(Win32 与 Win64)。NASM同样支持直接输出二进制文件(binary file),文件格式满足Intel十六进制与Motorola S-Record要求。NAMS的语法简单易懂,与Intel Software Developer Manual类似并且更加简明。NASM支持目前常用的x86架构扩展(x86 architectural extensional),对宏(macro)的支持较好。

原文:Intro To Win32 Assembly, Using NASM, Part 1

简介

目前有很多的计算机编程语言可供选择,其中之一就是汇编语言,并采用开源免费的用于Windows平台的汇编器NASM。很多人采用汇编语言的主要原因是在编写汇编语言源程序时,编程人员必须要从处理器的角度(processor‘s perspective)来思考问题及编写代码。

搭建开发环境所需软件

  1. NASM汇编器
  2. ALINK链接器
  3. Notepad++文本编辑器

Windows编程 - 什么是PE文件?

PE(portable execute)文件是用于Windows平台的可移植的可执行文件。PE文件一般包含(但不仅限于)头(header),以及code、data与idata节。

  1. 可执行的code节是文件内包含程序代码的区域。
  2. data节包含程序执行所需数据。
  3. idata节包含符号导入表(symbol import table)。
  4. bss节用于数据,但它不是磁盘上实际文件的一部分。

通常在PE文件中首先是头(header),其次是code节,然后是data节。当可执行文件位于内存中时,bss 节会从可执行文件中扩展。

idata节 - 什么是符号导入表?

每个 Windows 程序都会使用到 Windows 功能。例如,当 Windows 程序需要从磁盘读取文件时,它必须告知(contact)操作系统并"请求"它来执行。
在 Windows 下,告知操作系统的方法是调用 Windows 应用程序编程接口 (API) (或 Win32 API),要使用 Win32 API,需要从正确的动态链接库 (DLL) 导入我们计划使用的函数。

动态链接库 - 什么是 DLL?

DLL 是一个类似于 PE 的文件,但它不是作为普通程序运行的。DLL 本质上是函数库,除了Windows所提供的DLL之外,程序员也可以为他们的程序创建自己的 DLL。 DLL 的功能可以在程序运行时导入,也可以在程序启动期间导入。若要在运行时导入 DLL,程序需要使用 Win32 API 加载 DLL,然后使用 Win32 API 获取它需要调用的函数的内存地址。若要在程序启动时导入 DLL,PE 文件需要具有所需函数的导入表条目(import table entries)。

导入表需要包括函数名称及其容器 DLL 的名称,导入节(import section)的一部分是导入地址表(import address table)。当 Windows PE 加载程序将程序加载到内存中时,它将导入地址表中的条目替换为相应的 Win32 API 函数的内存地址。因此,当我们导入一个符号时,我们通过引用它来访问它,就像它是一个变量一样。

内存 - 什么是计算机内存?

基本上,任何一台计算机都应配有内存(memory),内存有点像计算机的"工作区"。当计算机做某事时,它都将会使用到内存。在将数据写入磁盘之前,必须将数据写入内存。要执行代码,需要先将代码加载到内存中。
要访问内存,需要指针。这些值可以是(在字长为 32 位的processor中)4 字节长的任何值。
操作系统(在这篇博客中为 Windows)将程序的内存限制在指定的地址空间,以确保我们的程序不会在重要内存位置对系统正常运行造成麻烦。
地址空间(address space)是内存地址的范围,每个字节在内存中都有唯一的内存地址。
因此,假设我们有一个容量是16字节的内存芯片,内存中各个字节存放的内容分别是:
12,17,84、244、123、93、83、194、
19、23、94、38、45、75、243、95
那么,内存地址为 7 的字节存放的值为 194,内存地址为 0 的字节存放的值为字节为 12,内存地址为 11 的字节存放的值为 38。

地址总线- 处理器如何访问内存?

处理器使用地址总线访问内存,而地址总线的大小有限。因此,如果尝试访问大于地址总线可访问的内存地址时,地址将被截断,这种截断被称为环绕(wrap-around)。
假设某计算机的地址总线有 2 位,并且尝试访问的内存地址为 101,则最终访问的内存地址为 01,并且地址的高位部分将被忽略,因此我们实际上访问的是物理地址为 01 的字节。
物理地址是内存中的实际地址。
虚拟地址是我们要在程序中给出的访问地址,虚拟地址被许多操作系统(包括 Windows)使用。

编译程序- 如何编译程序?

要编译程序,程序员通常会编译加入项目的所有文件(除了包含的文件)。编译器将源代码编译为对象文件(.s),然后使用链接器将所有对象文件链接到一个可执行 PE 文件中。
但是,除非我们正在构建一个大项目,否则单个源代码文件通常就足够了。
此外,链接器不知道程序执行的入口点(程序执行开始点)在什么位置,因此必须指定该入口点。在 NASM 中,可以使用特殊符号" .start:“,指定后程序将从” .start:"标签位开始运行,这在链接多个对象文件时非常有用。
利用汇编语言编写的文件,不需要经过编译(compile)过程。所谓的编译(compiling)实质上是将高级语言(higher-level language)编写的源文件编译成为由汇编语言所表示的源文件。

DATA与BSS - 为什么要使用 BSS?

利用data节(section),我们可以使用具有预定义值的变量,并在之后修改这些变量的值。在 bss节中,我们同样可以通过预定义的偏移量(地址)使用变量,但是我们不能预先定义这些值,这些值通常以 0 开始。使用 bss节有助于稍微减小程序文件的大小。

NASM语法 - 一些需要了解的事情

  • 方括号表示"在内存地址(at memory address)"。
  • 操作数大小前缀(BYTE、WORD、DWORD、QWORD)有时是必需的,有时是可选的。
  • <label_or_variable_name> 表示"地址(the address of)"。
  • 因此,[<label_or_variable_name>] 将意味着"在内存地址(at memory address of)"。
  • 每条指令允许的内存引用不超过1 个。
  • 美元符号 ($) 表示当前指令的地址。
  • %定义定义单行宏(类似于 C/C++中的#define)。
  • TIMES < action > 表示 times,do (另见,%rep)。
  • 可以使用"extern"告诉 NASM 尚未定义且存在于链接阶段的外部符号。

字节,字, 双字, 四字 - 这些是什么意思?

  • 1个字节(byte)大小为 8 位。
  • 1个字(word)大小为 16 位(2 字节)。
  • 1个双字(double-word)大小为 32 位(4 字节)。
  • 1个四字(quad-word)大小为 64 位(8 字节)。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值