我的汇编学习之路(2):主要术语和概念

对于不折不扣的汇编新手来说,第一部分中出现的很多概念可能不是很明白,于是我决定写更多有价值的文章。所以,让我们开始《我的汇编学习之路》的第二部分的学习。

术语和概念

当我写了第一篇之后,我从不同的读者那获得很多反馈,第一篇中有些部分不明白,这就是本文以及接下来几篇从一些术语的描述开始的原因。

寄存器(Register):寄存器是处理器内小容量的存储结构,处理器的主要功能是数据处理,处理器可以从内存中获得数据,但这是一种低速的操作,这就是为什么处理器为什么要有自己数据存储结构,称为“寄存器”。

L小端(Little-endian):我们可以假设内存是一个大的数组,它包含一个字节一个字节的数。每个地址存储了内存“数组”中的一个元素,每个元素一个字节。举例来说,我们有 4 字节数:AA 56 AB FF,在小端模式下最低位存放在低地址上:


1

2

3

4

0 FF

1 AB

2 56

3 AA

这里,0、1、2、3 是内存地址。

大端(Big-endian):大端存储数据与小端相反。所有上面的字节序在大端模式下是:


1

2

3

4

0 AA

1 56

2 AB

3 FF

系统调用(Syscall):系统调用是用户程序要求操作系统为其完成某些工作的一种方式。你可以在这里找到系统调用表。

(Stack):处理器中寄存器的个数非常有限。所以栈是一块连续的内存空间,可以通过特殊寄存器如 RSP、SS、RIP 等来寻址。在接下来的文章我会专门深入介绍栈。

(Section): 每个汇编程序都是由段来组成的,有以下的段:

  • data —— 用来声明初始化的数据或常量
  • bss —— 用来声明未初始化的变量
  • text —— 用来存放代码

通用寄存器(General-purpose register): 有 16 个通用寄存器:rax、rbx、rcx、rdx、rbp、rsp、rsi、rdi、r8、r9、r10、r11、r12、r13、r14、r15。

当然这不是与汇编语言有关的全部的术语和概念,如果在接下来的文章中遇到奇怪的不熟悉的词汇,我们再来解释这些词的意思。

数据类型

基本的数据类型有:字节(bytes)、字(words)、双字(doublewords)、四字(duadwords)以及双四字(double dualwords),它们的长度分别为:8位、2个字节、4个字节、8个字节、16个字节(128位)。

现在我们只使用整数,所以只看看它的表示。整型有两种类型:无符号和有符号。无符号整型是一个字节、字、双字、四字表示的无符号二进制数,它们能表 示的范围分别为:0~255、0~65,535、0~2^32-1、0~2^64-1。有符号整型是一个字节、字、双字、四字表示的有符号的二进制数。符 号位在负数的时候是置位的,在正数和0的时候是清零的。整数能表示的范围是:1个字节 -128~127,1个字 -32,768~32,767,1个双字 -2^31~2^31-1,1个四字 -2^63~2^63-1。

正如我上面提到的,每个汇编程序都是由段来组成的,它包含数据段、代码段、bss 段。我们先来看看数据段,这是主要用来定义初始化的常量。例如:


1

2

3

4

section .data

num1:   equ 100

num2:   equ 50

msg:    db"Sum is correct", 10

好了,这儿差不多清楚了,三个常量名字分别为 num1、num2 和 msg,值分别是 100、50 和 “Sum is correct”,10 。但是 db 、equ 又是什么呢?实际上,NASM 支持大量伪指令:

  • DB、DW、DD、DQ、DT、DO、DY 和 DZ —— 用来定义初始化数据的。例如:

1

2

3

4

5

;; Initialize 4 bytes 1h, 2h, 3h, 4h

db 0x01,0x02,0x03,0x04

;; Initialize word to 0x12 0x34

dw    0x1234

  • RESB、RESW、RESD、RESQ、REST、RESO、RESY、RESZ —— 用来定义非初始化变量
  • INCBIN —— 包含外部二进制文件
  • EQU —— 定义常量,例如:

1

2

;; now one is 1

one equ 1

  • TIMES —— 重复指令或数据(下一篇文章中描述)

算术操作

下面是算术操作指令的简单列表:

  • ADD —— 整数加
  • SUB —— 减
  • MUL —— 无符号乘
  • IMUL —— 有符号乘
  • DIV —— 无符号除
  • IDIV —— 有符号除
  • INC —— 自增
  • DEC —— 自减
  • NEG —— 取反

本文会用到一些,其它的在接下来的文章有所覆盖。

控制流

通常编程语言使用if、case、goto等等来改变程序的运行顺序,当然汇编也可以。这里我们提及到一些。有一个专门用来比较两个数大小的cmp指令,它被用来接着条件判断指令来决定是否跳转。例如:


1

2

;; compare rax with 50

cmprax, 50

cmp指令仅仅比较两个数,但是对它们的值没有影响,也不会根据比较的结果执行任何东西。为了在比较之后执行操作,有条件跳转指令,可以是下面的一个:

  • JE —— 如果相等
  • JZ —— 如果为零
  • JNE —— 如果不相等
  • JNZ —— 如果不为零
  • JG —— 如果第一个操作数比第二个大
  • JGE —— 如果第一个操作数比第二个大或者相等
  • JA —— 与 JG 指令相同,只不过比较的是无符号数
  • JAE —— 与 JGE 指令相同,只不过比较的是无符号数

例如如果我们想写 C 语言中类似于 if/else 的语句:


1

2

3

4

5

if(rax != 50) {

exit();

}else{

right();

}

在汇编中是这样的:


1

2

3

4

5

;; compare rax with 50

cmprax, 50

;; perform .exitifrax is not equal 50

jne .exit

jmp .right

也有一种无条件跳转的指令语法:


1

JMP LABEL

例如:


1

2

3

4

5

6

7

8

9

10

_start:

;; ....

;;dosomething and jump to .exitlabel

;; ....

jmp .exit

.exit:

mov    rax, 60

mov    rdi, 0

syscall

这里_start标签后有一些代码,这些代码会被执行到,汇编最后控制转向到.exit标签处,该标签后的代码开始执行。

通常无条件跳转用在循环中,例如我们有label标签,它后面有一些代码,代码执行完之后进行条件判断,如果条件不成立将跳到该段代码的起始处。循环将在后面文章中介绍。

示例

我们看个简单的例子:两个数相加,得到它们的和,然后与预定义的一个数进行比较,如果相等输出一些东西到屏幕上;如果不等退出。下面是例子的源代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

;initialised data section

section .data

; Define constants

num1:   equ 100

num2:   equ 50

; initialize message

msg:    db"Sum is correctn"

section .text

global _start

;; entry point

_start:

;setnum1‘s value to rax

mov rax, num1

;setnum2‘s value to rbx

mov rbx, num2

; getsumof rax and rbx, and store it‘s valueinrax

add rax, rbx

; compare rax and 150

cmprax, 150

; go to .exitlabelifrax and 150 are not equal

jne .exit

; go to .rightSum labelifrax and 150 are equal

jmp .rightSum

; Print message thatsumis correct

.rightSum:

;; write syscall

mov     rax, 1

;;filedescritor, standard output

mov     rdi, 1

;; message address

mov     rsi, msg

;; length of message

mov     rdx, 15

;; call write syscall

syscall

;exitfrom program

jmp .exit

;exitprocedure

.exit:

;exitsyscall

mov    rax, 60

;exitcode

mov    rdi, 0

; callexitsyscall

syscall

我们过一下这段代码。首先在数据段定义了三个数:num1、num2 和值为 “Sum is correctn” 的 msg。现在看到第 14 行,这是程序的入口的地方。我们将 num1 和 num2 的值放到通用寄存器 rax 和 rbx 中,使用 add 指令相加,在 add 指令执行完之后,rax 和 rbx 相加之和保存到 rax 中,即现在 num1 和 num2 的和存放在 rax 寄存器中。

好了,我们让 num1 是 100,num2 是 50,之和是 150,用 cmp 指令比较。在比较完 rax 和 150 之后,检查比较的结果,如果 rax 和 150 不等,我们跳转到.exit处,如果相等,跳到.rightSum标签处。

接着有两个标签:.exit和.rightSum。首先将 rax 设置为 60,这是 exit 系统调用号,以及将 rdi 设为 0,这是退出码。然后,.rightSUm相当简单,只是打印出Sum is corretn,如果你不能理解怎么工作的,看看第一篇文章

总结

这是 《我的汇编学习之路》 系列文章的第二篇,如果你有任何问题或建议,给我留言。

时间: 2024-08-10 23:29:55

我的汇编学习之路(2):主要术语和概念的相关文章

UART学习之路(一)基本概念

第一篇博客,首先记录一下这一个多星期来的学习内容. UART学习之路第一篇,是UART的基本概念介绍.后续会用STM32F407的串口与PC机通信.最后使用Verilog HDL写出串口发送模块和接收模块,完成仿真,在Zedboard板上完成通信. 首先先明确什么是UART,COM口,TTL,RS-232. 通用异步收发传送器(Universal Asynchronous Receiver/Transmitter, UART)有4个管脚分别为VCC,GND,TX,RX,电平标准为TTL电平.低电

汇编学习之路--目录

教材:<汇编语言> 王爽 第三版 Charpter 1. 基础知识 1.1 : 机器语言 1.2 : 汇编语言的产生 1.3 : 汇编语言的组成 1.4 : 存储器 1.5 : 指令和数据 1.6 : 存储单元 1.7 : CPU对于存储器的读写 1.8 : 地址总线 1.9 : 数据总线 1.10 : 控制总线 1.11 : 内存地址空间(概述) 1.12 : 主板 1.13 : 接口卡 1.14 : 各类存储器芯片 1.15 : 内存地址空间 --------------- 更新中 原文地

OllyDbg学习之路-3

6.比较和跳转指令 (1)cmp eax,ecx 相当于sub eax,ecx 但不保存结果到第一个操作数. 根据结果改变零标志位(Z).相等时,零标志位置1. 根据结果正负改变符号标志位(S).运算结果为负时,置为1. cmp允许寄存器与byte.word.dword类型的内存单元做比较. eg:cmp ax,word ptr ds:[405000] (2)test 两个数值进行与操作,结果不保存,改变相应标志位 eg:test eax,eax 这个指令可以确定eax是否为0 (3)关于寻找跳

Azure云平台学习之路(三)——Cloud Services

1.什么是云服务? 能够部署高度可用的且可无限缩放的应用程序和API.简而言之,就是你写的CMD程序按照一定的框架进行少量修改就能运行在Azure云平台上. 2.Azure云服务有什么特点? (1)专注应用程序而不是硬件,PaaS的一种. (2)支持多种框架和语言. (3)集成了运行状况监视和负载平衡. (4)自动缩放优化成本和性能 3.建立云服务之前,我们需要建立一个云存储,来记录我们的程序的日志信息(当然,这不是必须的) (1)选择左边导航栏的"存储".主面板上显示的是所有已有的存

linux学习之路之LVM

试想一种情况,当初我们在规划磁盘的时候,只给某一个磁盘或分区之划分了30G的容量,但是后来,随着业务的需求,该磁盘或者分区的使用量会越来越大,等到以后再有数据存放时,发现该磁盘或者分区的容量不够用,此时该怎么办了?可以新增一个磁盘,经过格式化,挂载等过程就可以使用这个磁盘了,再将原来磁盘的数据完全的复制过来.等到后来又发现,规划的磁盘又太大了,然后又使用上述方法来减少磁盘的大小.虽然这种方法可行,但是效率低,比较复杂.不应该是我们首选的方法. 当然,我们可以这样做,将多个磁盘或者分区(PV)组合

我的算法学习之路

关于 严格来说,本文题目应该是我的数据结构和算法学习之路,但这个写法实在太绕口--况且CS中的算法往往暗指数据结构和算法(例如算法导论指的实际上是数据结构和算法导论),所以我认为本文题目是合理的. 这篇文章讲了什么? 我这些年学习数据结构和算法的总结. 一些不错的算法书籍和教程. 算法的重要性. 初学 第一次接触数据结构是在大二下学期的数据结构课程.然而这门课程并没有让我入门--当时自己正忙于倒卖各种MP3和耳机,对于这些课程根本就不屑一顾--反正最后考试划个重点也能过,于是这门整个计算机专业本

一个女大学生的代码学习之路(二)

首先说一下,写这种文章是由于我在四月四日晚上,在手动搭建自己的第一个ssh项目的时候,遇到了一个配置的问题,怎么解决也弄不好,当时是四号晚上九点,我看了一眼表,我就想两个小时之内,我要是能搞定就算行了,但是其实,我搞到三点才OK(凌晨),那时候已经是五号了,转天是一家子去扫墓的时候,结果我居然以这种一个理由没有去,理由是我太累了么?我只是就是搭了一个架子,就是由于我的包太混乱了,导致不兼容,所以tomcat总也不启动,你可能认为好笑,这么简单一个问题怎么就费这多多时间呢,但是作为一个刚接触三框架

基于8086CPU微处理器的汇编学习之MOV指令

汇编指令:MOV的作用是往某个寄存器中存入数值. 格式:mov  寄存器名,数值                数值-->寄存器 mov  寄存器A,存器寄B          B-->A PS:必须前后位数匹配,如: mov   ah,bx     ;error   ah is 8 bit,bx is 16 bit mov   ah, bh    ;right    ah and bh all is 8  bit mov   cx,dx     ;right     cx and dx al

kafka学习之路(二)——提高

kafka学习之路(二)--提高 消息发送流程 因为Kafka内在就是分布式的,一个Kafka集群通常包括多个代理.为了均衡负载,将话题分成多个分区,每个代理存储一或多个分区.多个生产者和消费者能够同时生产和获取消息.     过程: 1.Producer根据指定的partition方法(round-robin.hash等),将消息发布到指定topic的partition里面 2.kafka集群接收到Producer发过来的消息后,将其持久化到硬盘,并保留消息指定时长(可配置),而不关注消息是否