采⽤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)的⽀持较好。
原⽂:
简介
⽬前有很多的计算机编程语⾔可供选择,其中之⼀就是汇编语⾔,并采⽤开源免费的⽤于Windows平台的汇编器NASM。很多⼈采⽤汇编语⾔的主要原因是在编写汇编语⾔源程序时,编程⼈员必须要从处理器的⾓度(processor‘s perspective)来思考问题及编写代码。
汇编table指令什么意思搭建开发环境所需软件
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 字节)。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。