汇编程序设计与计算机体系结构软件工程师教程笔记:汇编语法基础知识

《汇编程序设计与计算机体系结构: 软件工程师教程》这本书是由Brain R.Hall和Kevin J.Slonka著,由爱飞翔译。中文版是2019年出版的。个人感觉这本书真不错,书中介绍了三种汇编器GAS、NASM、MASM异同,全部示例代码都放在了GitHub上,包括x86和x86_64,并且给出了较多的网络参考资料链接。这里只摘记了NASM和MASM,测试代码仅支持Windows和Linux的x86_64。

3. 汇编语言及其语法的基础知识

3.2 基本元素:

汇编代码的五大支柱:保留字(reserved word)、标识符(identifier)、命令(directive, 也称为指示或伪操作)、区段(section或segment, 简称段)以及指令(instruction)。

(1). 保留字:是一种具备特定用途的字词。例如MOV就是个保留字,它代表一条特定的指令,即MOV指令。你不能把它当成变量名来用,也不能做其它用途。汇编语言的保留字不区分大小写。指令(例如MOV)、命令(例如PROC)、寄存器(例如eax)、属性(例如可以当作.MODEL命令参数值的FLAT)等,都是保留字。

(2). 标识符:是由程序员所定义的名称,用来表示变量、常量及过程等事物,它最多可以包含247个字符。第一个字符不能是数字,且必须从英文字母(大写的A至Z及小写的a至z)、下划线(_)、问号(?)、at符号(@)及美元符号($)这五种中选择,其后的字符则可以使用数字

(3). 命令:是与指令集无关的一些操作,可以指挥汇编器去做某件事,例如定义变量、指明内存段等。

下表列出了32位程序MASM版本特有的命令:用MASM编写64位程序的时候不需要使用此表中的命令。

汇编程序设计与计算机体系结构软件工程师教程笔记:汇编语法基础知识_第1张图片

(4). 程序段(program section或program segment):是用相关命令所标出的特殊段落。汇编器预先定义了几种这样的段落。下表列出了撰写汇编代码时常有的几种程序段:

汇编程序设计与计算机体系结构软件工程师教程笔记:汇编语法基础知识_第2张图片

(5). 指令:是程序中的可执行语句。指令由两个基本部分组成,其语法如下:”mnemonic  [operands]”,其中mnemonic(助记符)是指令的名称,开发者用它来指代某个架构所支持的一套指令集里的一条指令。助记符通常是个缩写形式或首字母缩略形式的词,实际上也可以认为是数字形式的操作码所对应的英语写法。有些指令不需要操作数,有些则需要一个、两个或三个操作数。

字面量(literal value, 字面值):也叫做立即值(immediate, 立即数),用来表示那些由开发者明确指定的值,例如整数、实数、字符、字符串等。

整数字面量(integer literal):一般写为十进制(或者说以10为底的进制)的整数。在有些情况下也可以(甚至是必须)采用其它进制来写。MASM及NASM允许开发者在字面量之后写上一个表示基数的字符,以指出这个字面量所采用的进制。如二进制b、十进制d、十六进制h、八进制o或q。有一种情况要注意,十六进制数的数位中可能会出现A至F这几种英文字符。如果某个十六进制数(例如内存地址)是以英文字符开头的,那么汇编器就会把它当成标识符看待,为了令其能够正确地将该值解读为字面量,你应该在前面添一个0.

字符字面量(character literal):是由单个字符所构成的值,与整数字面量一样,也用来表示那种开发者在编写程序代码的时候就已经很清楚的值。MASM与NASM中的字符字面量可以用一对单引号括起来,也可以用一对双引号括起来,这两种写法是等效的。字符在存储器中是以整数形式的ASCII编码来表示的。

字符串字面量(string literal):是由多个字符字面量所组成的,通常用来表示单词或短语。MASM与NASM的字符串与单个字符类似,也可以用一对单引号或双引号括起来。如果字符串的内容本身就有引号,那么对于MASM及NASM来说,你必须用另外一种引号把这个字符串括起来。字符串通常保存成字节数组,其中的每个字节都与字符串中处在该位置上的字符相对应,字节的内容就是字符的ASCII码。

标签(label):可以用来划分代码,以表达某种与编程或设计有关的想法。它不仅可以令代码读起来更加清晰,而且有的时候还能够帮助开发者实现跳转或循环等功能,使得程序可以跳到标签所标识的这个地方。标签的写法是在标识符后面跟一个冒号。标签可以单独占据一行也可以与指令写在同一行。NASM的标签用在.text段里    的标签区分大小写,MASM的标签写在.code段里则不区分大小写

汇编语言的注释可以分成两种:单行注释与多行注释。MASM及NASM的单行注释以分号(;)开头。注释可以单独占据一行也可以写在某行代码的后面。多行注释只能在MASM中用。MASM的多行注释必须与其它代码分别写在不同的行里,而且要由四部分组成:COMMENT、起始字符、注释文本、终止字符。起始字符与终止字符必须采用同一种字符,而且要注意不能与注释文本中的任何一个字符相同(否则注释就会提前结束)。MASM的多行注释习惯上采用感叹号(!)作为起、止字符。

3.3 定义数据:

汇编语言的数据类型根据数据的大小来确定(例如8位、16位、32位)。下表列出了各种汇编器所支持的数据类型:无论采用哪种汇编器,.data段里定义的变量都必须予以初始化,也就是必须具备初始值

汇编程序设计与计算机体系结构软件工程师教程笔记:汇编语法基础知识_第3张图片

变量采用下列语法来定义:

NASM:[标识符:] 命令 初始化器 [, 初始化器] …

MASM:[标识符] 命令 初始化器 [, 初始化器] …

一个标识符后面带有多个初始化器的写法可以用来创建数组(array),也就是创建一系列大小相同的值。这些值都可以通过数组的名称加以引用,该名称本身指的是序列中的第一个值(或序列中的第一个值在内存中的位置)。充当数组名称的标识符其实是指向数组中首个值的引用,它表示的是该值在内存中的位置。

有的时候,程序中需要定义未初始化的变量。这种变量不具备初始值,它主要是为了在内存中预留一定的空间以供开发者使用。对于这种变量,不同的汇编器所采用的定义方式之间有很大的区别。NASM要求.data段里的变量必须用明确的值来初始化,而MASM则允许开发者在该段中采用问号(?)充当变量的初始化器来定义未初始化的变量

MASM的初始化器可以用DUP括起来,以便反复创建大小与内容均相同的多个值。凡是有效的初始化器都可以用DUP命令加以重复,这也包括问号。

NASM要求未初始化的变量必须创建在.bss段中(bss的意思是Block Started by Symbol,以符号开始的块),而且要用特定的命令来创建,如下表所示:能够通过相应的命令,以单个变量或数组的形式来预留各种数据类型的未初始化空间。

汇编程序设计与计算机体系结构软件工程师教程笔记:汇编语法基础知识_第4张图片

字符串是以BYTE(字节)数组的方式存储的。字符串必须以null结尾,也就是说,其最后一个字节必须是值为0的ASCII码。不同的汇编器采用不同的方式来定义这种字符串。MASM与NASM则是直接用字面量0来设置最后一个字节。一个涉及字符串的重要问题是换行。不同的汇编器采用不同的方式换行。MASM用十六进制码0Dh与0Ah来表示CR/LF这两个符号并以此实现换行(CR的意思是carriage-return, 回车)。NASM则只用0Ah这一个十六进制码(也就是LF)表示换行

符号常量(symbolic constant)可以在MASM版本的汇编代码里取代某些变量,用以表示程序执行期间绝对不会变化的值。x86的符号常量能够表示32位整数,x86_64的符号常量能够表示64位整数,常量所表示的都是基于整数的数据。你可以用等号(=)定义这样的常量。MASM里的符号常量不占内存,因为MASM在对代码作汇编的时候,会把所有出现符号常量的地方都改成该常量所对应的实际值。采用等号来定义符号常量的写法只适用于MASM汇编器。此外,MASM的符号常量还可以用来表示字符串值。

所有的汇编器都可以把表达式的值表示成符号常量。符号必须用EQU命令来定义。与定义变量时的要求不同,用EQU所创建的符号既可以出现在数据段也可以出现在代码段(对于MASM汇编器,它可以出现在.data与.code段,对于NASM汇编器,它可以出现在SECTION .data与SECTION .text段)。这些汇编器在对代码作汇编的时候会把每一个出现这种符号的地方都替换成对应的表达式。建议只针对数值表达式来使用EQU命令。EQU命令还有一个用途,是通过创建符号常量来表示某个标识符所指代的数据占用了多大的内存空间。当前位置计数器(current location counter)用来指代位置计数器的当前内存地址(MASM及NASM用美元符号$表示),将该地址与前一个字符串的起始内存地址相减即可算出字符串所占据的字节数。MASM可以通过等号(=)把计算结果定义成标识符。

MASM还提供了一种写法,能够创建动态符号,称为文本宏(text macro)。由TEXTEQU命令所创建的符号可以表示涉及其它符号的表达式,甚至还可以表示指令。注意,由于指令不是整数表达式,因此它的左右两端是用尖括号括起来的。

Windows上使用VS编译MASM汇编操作步骤

(1). 创建一个Win32控制台应用程序AssemblyLanguage_Test;

(2). 右键单击该项目-->生成依赖项-->生成自定义:勾选masm复选框,点击确定;

(3). 添加一个新建文件funset.asm;

(4). 右击funset.asm-->属性:常规:项类型调整为:Microsoft Macro Assembler;

(5). 右键单击该项目-->属性:链接器:系统:子系统:调整为:窗口 (/SUBSYSTEM:WINDOWS);链接器:高级:入口点:填写为_main;

(6). 向funset.asm编写汇编代码,测试代码来自于:https://github.com/brianrhall/Assembly/blob/master/Chapter_3/Program%203.2/x86_64/Program_3.2_MASM.asm

可以在适当的位置设置断点,F5运行程序,打开寄存器、内存、反汇编、监视等窗口查看相关内容;可以在寄存器窗口中单击鼠标右键,选择”标志”查看标志寄存器的值,结果如下图所示:

汇编程序设计与计算机体系结构软件工程师教程笔记:汇编语法基础知识_第5张图片

Ubuntu上编译NASM汇编操作步骤

(1). 新建文件funset.asm,测试代码来自于:https://github.com/brianrhall/Assembly/blob/master/Chapter_3/Program%203.2/x86_64/Program_3.2_NASM.asm

(2). 脚本文件build.sh内容如下:

#! /bin/bash

nasm -f elf64 -o funset.o funset.asm
ld -e _main -melf_x86_64 -o funset funset.o
#./funset

可以通过gdb查看寄存器、变量等相关值,结果如下图所示:

汇编程序设计与计算机体系结构软件工程师教程笔记:汇编语法基础知识_第6张图片

GitHub:https://github.com/fengbingchun/CUDA_Test

你可能感兴趣的:(SIMD/Assembly,Language,Assembly)