数据处理的两个基本问题
处理的数据在什么地方?
要处理的数据长度是多少?
bx、si、di 和 bp
只有这个 4 个寄存器可以用来在 [...] 中进行内存单元寻址。
123456mov ax, [bx]mov ax, [bx+si]mov ax, [bx+di]mov ax, [bp]mov ax, [bp+si]mov ax, [bp+di]
错误用法:
1mov ax, [cx]
在 [...] 中,这 4 个寄存器可以单个出现或者以 4 种组合出现:bx 和 si、bx 和 di、bp 和 si、bp 和 di。
以下都是正确的指令:
123456789101112mov ax, [bx]mov ax, [si]mov ax, [di]mov ax, [bp]mov ax, [bx+si]mov ax, [bx+di]mov ax, [bp+si]mov ax, [bp+di]mov ax, [bx+si+idata]mov ax, [bx+di+idata]mov ax, [bp+si+idata]mov ax, [bp+di+idata]
在 [...] 中使用寄存器 bp,段地址默认从 ...
更灵活的定位内存地址的方法
and 和 or 指令
将 al 和操作数进行按位与。
12mov al, 01100011band al, 00111011b
将 al 和操作数进行按位或。
12mov al, 01100011bor al, 00111011b
以字符的形式给出数据
12db 'unIX'db 'foRK'
相当于
12db 75h, 6eh, 49h, 58hdb 66h, 6fh, 52h, 4bh
1mov al, 'a'
相当于
1mov al, 61h
[bx+idata]
[bx+idata] 表示一个内存单元,它的偏移地址为 (bx) + idata。
将一个内存单元的内容送入 ax,内存单元长度为一个字,偏移地址为 bx 中的数值加上 200,段地址在 ds 中。
1mov ax, [bx+200]
字符串大小写转换问题
1234567891011121314151617181920212223242526assume cs:codesg, ds:datasgdatasg segment db 'BaS ...
包含多个段的程序
在代码段中存放数据、栈
使用 dw 关键字可以定义字型数据,dw 全称为 define word。
1dw 0123h, 0456h
定义数据、栈,指定程序入口:
123456789101112131415161718192021assume cs:codesgcodesg segment dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h dw 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0start: mov ax, cs mov ss, ax mov sp, 30h mov bx, 0 mov cx, 8 s: push cs:[bx] add bx, 2 loop s mov bx, 0 mov cx, 8 s0: pop cs:[bx] add bx, 2 loop s0 mov ax, 4c0 ...
[bx] 和 loop 指令
内存单元
描述一个内存单元需要两种信息:
内存单元的地址
内存单元的长度(类型:字、字节)
[bx] 可以标识一个内存单元,偏移地址在 bx 寄存器中,段地址在 ds 寄存器中。
约定符号
(ax) 表示取 ax 寄存器中的内容。
idata 表示常量。
[bx]
1mov ax, [bx]
bx 寄存器中存放的数据作为偏移地址 EA,ds 寄存器中的数据作为段地址 SA,将 SA:EA 中的数据送入 ax 中,即 (ax) = ((ds)*16 + (bx))。
1mov [bx], ax
bx 寄存器中存放的数据作为偏移地址 EA,ds 寄存器中的数据作为段地址 SA,将 ax 寄存器中的数据送入内存 SA:EA 处,即 ((ds)*16 + (bx)) = (ax)。
loop 指令
loop 指令格式:
1loop 标号
CPU 执行 loop 指令时的操作:
(cx) = (cx) - 1
判断 cx 寄存器中的值,不为零就转到标号执行,为零向下执行
计算 2122^12212
12345678910assume cs:codecode segment ...
第一个汇编程序
第一个程序
源程序是文本文件,编译器将源程序编译成目标文件,内容为机器码,连接器将多个目标文件以及库文件连接在一起,并将这些内容处理为可执行文件。
DOS 中加载 EXE 程序的过程:
找到一段起始地址为 SA:0000 的空闲内存空间。
在这段内存前 256 字节,创建程序段前缀(PSP)的数据区,DOS 利用 PSP 与程序通信。
在 PSP 数据区的后面,将程序装入。程序起始地址为:SA+10H:0。
存储段地址 DS = SA,初始化 CS:IP 为程序入口地址。
汇编源代码语法
汇编代码片段:
12345678910111213141516assume cs:codesgcodesg segment mov ax,2000H mov ss,ax mov sp,0 add sp,10 pop ax pop bx push ax push bx pop ax pop bx mov ax,4c00H int 21Hcodesg endsend
伪指令:
伪指令不对应机器码,由编译器执行相关操作。
assume 将定义的 codesg 段与 CS 寄存 ...
寄存器内存访问
内存中的字存储
高 8 位存高位字节,低 8 位存低位字节。一个字需要两个连续的内存单元。低位字节存在低地址单元,高位字节存放在高地址单元。
DS 和 [address]
mov 指令可以将一个内存单元中的内容送入一个寄存器。
1mov ax, [0]
[…] 表示内存单元,其中的 0 表示内存单元的偏移地址。指令执行时,8086CPU 自动从 DS 寄存器中取数据作为内存单元的段地址。
123mov bx, 1000Hmov ds, bxmov ax, [0]
只能将一个寄存器内的值送入 ds 寄存器。
将 ax 寄存器中的值送入内存单元 10000H:
123mov bx, 1000Hmov ds, bxmov [0], ax
字的传送
在 mov 指令中给出 16 位寄存器就可以进行 16 位数据传送。
1234mov bx 1000Hmov ds, bxmov ax, [0] ; 1000:0 处的字型数据送入 ax 寄存器mov [0], cx ; cx 寄存器的数据送入 1000:0 处
mov、add、sub 指令
指令
参数一
参数二
mov ...
每日打卡-LeetCode-377-组合总数4
f[i] 表示凑出 i 的所有方案数。按照每种方案的最后一个数是什么划分子问题。当最后一个数是 a[j] 时,考虑如何凑出 i - a[j],方案的数量等于 f[i - a[j]]。
12345678910111213141516class Solution { public: int combinationSum4(vector<int>& nums, int m) { vector<unsigned> f(m + 1); // f[i] 表示凑出 i 的所有方案数 f[0] = 1; for (int i = 1; i <= m; i++) { for (auto j : nums) { if (i >= j) { f[i] += f[i - j]; } } } return f[m]; }};
寄存器
寄存器
CPU 由运算器、控制器、寄存器构成,之间通过内部总线相连。
运算器进行信息处理
寄存器进行信息存储
控制器控制各种器件进行工作
内部总线连接各种器件,传送数据
8086CPU 有 14 个寄存器:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。
通用寄存器
8086CPU 所有寄存器都是 16 位的,可以存放两个字节。AX、BX、CX、DX 寄存器用来存放一般数据,称为通用寄存器。
8086CPU 上一代寄存器都是 8 位的,为保证兼容,AX、BX、CX、DX 寄存器都可以分为两个独立使用的 8 位寄存器。
AX 分为 AH、AL
BX 分为 BH、BL
CX 分为 CH、CL
DX 分为 DH、DL
L 表示 low,低 8 位;H 表示 high,高 8 位。
字
8086CPU 可以一次性处理两种尺寸的数据:
字节,一个字节由 8 个 bit 组成,可以存放在 8 位寄存器。
字,一个字由两个字节组成,高位字节、低位字节。
一个字可以存在一个 16 位寄存器中。
汇编指令
汇编指令
高级语言描述
...
每日打卡-LeetCode-368-最大整除子集
最大整除子集
f[i] 表示在输入数组 nums 升序排列的前提下,以 nums[i] 为最大整数的「整除子集」的大小。
123456789101112131415161718192021222324252627282930313233class Solution { public: vector<int> largestDivisibleSubset(vector<int>& nums) { int n = nums.size(); vector<int> f(n + 1, 1); sort(nums.begin(), nums.end()); int maxSize = 1; int maxVal = f[0]; for (int i = 1; i < n; i++) { for (int j = 0; j < i; j++) { if (nums[i] % nums[j] == 0) { f[i] ...
每日打卡-LeetCode-91-解码方法
解码方法
12345678910111213141516171819class Solution { public: int numDecodings(string s) { int n = s.size(); s = ' ' + s; vector<int> f(n + 1); f[0] = 1; for (int i = 1; i <= n; i++) { // 如果当前字符是 1 ~ 9,那么可以自己单独形成一种解码方法 if (s[i] >= '1' && s[i] <= '9') f[i] += f[i - 1]; if (i > 1) { // 如果当前字符与前一个字符连起来的数值在 10 ~ 26,那么可以与之形成一种解码方法 int t = (s[i - 1] - '0') * 10 + (s[i] - ...