汇编语言_简单入门相关_zcylkcsj

关于汇编语言的CPTH机的一点学习记录


简要复习常用的汇编指令:

·堆栈相关指令 对于指令的详细了解,应该查阅Intel发布的指令手册。但是从头开始阅读那些手册是一件令人望而生畏的事情。读者暂时可以只初步了解,忽略一些细节,当实际用到的时候,再具体查阅相关指令。

  • push:把一个32位的操作数压入堆栈中。这个操作导致esp被减4。Esp被形象地成为栈顶。我们认为顶部是地址小的区域,那么,压入堆栈的数据越多,这个堆栈也就越堆越高,esp也就越来越小。在32位平台上,esp每次减少4字节。
  • pop:相反,esp被加4,一个数据出栈。Pop的参数一般是一个寄存器,栈顶的数据被弹出到这个寄存器中。

一般不会把sub、add这样的算术指令,以及call、ret这样的跳转指令归入堆栈相关指令中。但是实际上在函数参数传递过程中,sub和add是最常用来操作堆栈;call和ret对堆栈也有影响。所以这里做特殊处理。

  • sub:减法。第一个参数是被减数所在的寄存器;第二个参数是减数。(对应的还有add指令。)
  • add:加法。
  • ret:返回。相当于跳转回调用函数的地方。(对应的call指令来调用函数,返回到call之后的下一条指令。)
  • call:调用函数。

说道这里,有必要详述一些指令对堆栈的影响。某些指令会“自动”地操作堆栈,这就是call和jmp的不同之处。Call指令会把它的下一条指令的地址压入堆栈中,然后跳转到它调用的函数的开头处;而单纯的jmp是不会这样做的。同时,ret会自动地弹出返回地址。 (小提示:call的本质相当于push+jmp。ret的本质相当于pop+jmp) 不但push、pop、call和ret会操作堆栈,sub和add也可以用于操作堆栈。如果我们要一次在堆栈中分配4个4字节长整型空间,那么没有必要4次调用push,很简单地把esp减去44=16即可。当然,也可以同样地用add指令来恢复它。这常常用于分配函数局部变量空间,因为C语言函数的局部变量保存在堆栈里。 ··*数据传送指令

  • mov:数据移动。第一个参数是目的,第二个参数是来源。在C语言中相当于赋值号。这是最广为人知的指令。
  • xor:异或。这虽是逻辑运算指令,但是有趣的是,xor eax,eax这样的操作常常用来代替mov eax,0。好处是速度更快,占用字节数更少。
  • lea:取地址(第二个参数)后放入到前面的寄存器(第一个参数)中。

(小提示:见到xor eax,eax,应该马上明白这是清零操作。) 但是实际上,有时候用lea用来做和mov同样的事情,比如赋值。看下面一条指令: lea dei,[ebp-0cch] 方括弧表示存储器,也就是ebp-0cch这个地址所指向的存储内容。但是lea要求取[ebp-0cch]的地址,那么地址就是ebp-0cch,这个地址将被放入到edi中。换句话说,这等同于: mov dei,ebp-0cch 但是以上mov指令是错误的,因为mov不支持后一个操作数写成寄存器减去数字。但是lea支持,所以可以用lea来代替它。 指令的操作数能采用的运算符号有非常复杂的限制。如果需要使用,应该查询指令手册。 为了讲解stos,下面解说前面提到的代码: mov ecx,30h mov eax,0cccccccch rep stos dword ptr es:[edi] Stos是串存储指令,它的功能是将eax中的数据放入edi所指的地址中,同时,edi会增加4(字节数)。Rep使指令重复执行ecx中填写的次数。方括弧表示存储器,这个地址实际上就是edi的内容所指向的地址。这里的stos其实是对应的stosd,其他还有stosb、stosw,分别对应于处理4、1、2个字节,这里对堆栈中30h4(0c0h)个字节初始化为0cch(也就是int3指令的机器码),这样发生意外时执行堆栈里面的内容会引发调试中断。 *···跳转与比较指令 部分跳转指令如下:

  • jmp:无条件跳转。这也是多年后我依然未忘记的少量指令之一。
  • jg:顾名思义,大于的时候跳转。通常前面有一条比较指令。
  • jl:顾名思义,小于的时候跳转。通常前面有一条比较指令。
  • jge:顾名思义,大于等于的时候跳转。通常前面有一条比较指令。

类似的指令还有一些,这里就不介绍了。 下面介绍一条比较指令。

  • cmp:顾名思义,比较。往往是jg、jl、jge之类的条件跳转指令的执行条件。

[caption id=”attachment_646” align=”alignnone” width=”607”]dream 1. 对战说明
一般用于:组成原理、操作系统的保护;
还用于数据指令。
bakke:堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除。在单片机应用中,堆栈是个特殊的存储区,主要功能是暂时存放数据和地址,通常用来保护断点和现场。要点:堆,队列优先,先进先出(FIFO—first in first out)[1] 。栈,先进后出(FILO—First-In/Last-Out)。[/caption]

2. 二进制是b(binary),十六进制是h(hexdecimal)。十进制一般不需标示,特殊情况下需要区分时标注d(decimal)。

3. 补充对于 汇编语言加中括号表示什么 例如ADD AL,[SI] MOV[20H],AL还有小括号呢 例如DS=(SI+2)

一般说来,加方括号 [ ] 表示一种间接的取操作数方式,有点类似于C语言中的指针概念. 第一条指令 ADD AL ,[SI] 中,[SI] 表示寄存器间接寻址. 也就是说,与AL中内容相加的加数,不是SI寄存器的内容,而是以SI的内容作为地址指针的内存操作数. 假设SI的内容是1234H,这条加法指令,不是将1234H加到AL里(也加不了,数据类型不对),而是以1234H作为地址,从内存的数据段(DS所指)中,段内偏移地址为1234H的那个内存单元中取出一个字节的数据来,加到AL中. 同样的,第二条指令 MOV [20H],AL,是将AL中的内容传送到内存里的一个单元中去.这个单元的有效地址就是[20H]. 这里,加了方括号的20H,不是运算所用的数据,而是数据的地址. =================== 对问题补充的回复: AL是不可能加方括号的. 8086汇编中,能加方括号的只有4个寄存器:SI,DI,BX,BP 常数也可以加方括号,比如 [020H] 另外,变量名可以加方括号,但与上面两种情况不同,加了方括号的变量名,意义不变. 至于方括号内,可以出现BX+DI,SI+2这样的表达式,这是一些不同的寻址方式. SI 是寄存器寻址 [SI]是寄存器间接寻址 [SI+2]是相对的寄存器间接寻址,又称直接变址寻址,它也可以写成2[SI]这样的形式 [BX+SI]是基址变址寻址,也可写成[BX][SI] [BX+SI+20H]是相对的基址变址寻址,可以写成20H[BX][SI]之类的形式,将20H换成变量名也可以.

mov ax, [bx];该指令中,bx中存储的值为一个偏移地址,该指令是将bx中存储的数据段偏移地址所对应的存储器中的值传送给ax。
mov ax,bx是把bx中存储的值传送给ax
不能互换


--- c:\\users\\acanprince\\desktop\\文档_ssd\\2017_春\\zuchengyuanli\\zuchengyuanli\\main.c

include

int main()
{
00851680 push ebp
00851681 mov ebp,esp
00851683 sub esp,108h
00851689 push ebx
0085168A push esi
0085168B push edi
0085168C lea edi,[ebp-108h]
00851692 mov ecx,42h
00851697 mov eax,0CCCCCCCCh
0085169C rep stos dword ptr es:[edi]
int a[10] = {25,-12,16,38,-22,56,46,109,127,-1};
0085169E mov dword ptr [a],19h
008516A5 mov dword ptr [ebp-28h],0FFFFFFF4h
008516AC mov dword ptr [ebp-24h],10h
008516B3 mov dword ptr [ebp-20h],26h
008516BA mov dword ptr [ebp-1Ch],0FFFFFFEAh
008516C1 mov dword ptr [ebp-18h],38h
008516C8 mov dword ptr [ebp-14h],2Eh
008516CF mov dword ptr [ebp-10h],6Dh
008516D6 mov dword ptr [ebp-0Ch],7Fh
008516DD mov dword ptr [ebp-8],0FFFFFFFFh
int i = 0,sum = 0;
008516E4 mov dword ptr [i],0
008516EB mov dword ptr [sum],0
for (; i < 10; i++)
008516F2 jmp main+7Dh (08516FDh)
008516F4 mov eax,dword ptr [i]
008516F7 add eax,1
008516FA mov dword ptr [i],eax
008516FD cmp dword ptr [i],0Ah
00851701 jge main+92h (0851712h)
{
sum += a[i];
00851703 mov eax,dword ptr [i]
00851706 mov ecx,dword ptr [sum]
00851709 add ecx,dword ptr a[eax*4]
0085170D mov dword ptr [sum],ecx
}
00851710 jmp main+74h (08516F4h)
return 0;
00851712 xor eax,eax
}
00851714 push edx
00851715 mov ecx,ebp
00851717 push eax
00851718 lea edx,ds:[85172Ch]
0085171E call @_RTC_CheckStackVars@8 (0851244h)
00851723 pop eax
00851724 pop edx
00851725 pop edi
00851726 pop esi
00851727 pop ebx
00851728 mov esp,ebp
0085172A pop ebp
0085172B ret
0085172C add dword ptr [eax],eax
0085172E add byte ptr [eax],al
00851730 xor al,17h
00851732 test dword ptr [eax],eax
00851734 aamb 0FFh
00851736 ?? ??
00851737 jmp fword ptr [eax]
00851739 add byte ptr [eax],al
0085173B add byte ptr [eax+17h],al
0085173E test dword ptr [eax],eax
00851740 popad
00851741 add ah,cl
--- 无源文件 ———————————————————————————————————-

有关于课程设计:

1. MOV R2,#0A
2. loop:
- MOV a,R2
- ADD a,#7F //数据段起始地址
- MOV R3,a
- MOV a,@R3
- ADDC a,#80
JC ##; //判断正负
MOV a,@R3
ADD a,R1
MOV R1,a
MOV a,#00
ADDC a,R0
MOV R0,a
MOV a,R2
SUB a,#01
JZ out; //跳出的
MOV R2,a
JMP loop;

:

MOV a,@R3
SUB a,#80
CPL a
ADD a,#1
ADD a,R1
MOV R1,a
MOV a,#FF
ADDC a,R0
MOV R0,a
MOV a,R2
SUB a,#01
JZ out;        //跳出的
MOV R2,a
JMP loop;

3. out:
MOV a,R0
ADD a,#80
JC ###;
//THE END

:

MOV a,R0
CPL a
MOV R0,a
MOV a,R1
CPL a
ADD a,#01      //低位
MOV R1,a
MOV a,R0
ADDC a,#80      //+C  +符号位
MOV R0,a;       //负数取原码 结束

# 题目
10个单字节有符号数的加法,要求数组里面有负数且和的绝对值要大于255D,数据用源码表示,计算过程要求使用补码。
# ————-代码段————
00 8E //MOV R2, #0A
01 0A
02 72 //MOV A, R2
03 1C //ADD A, #7F
04 7F
05 83 //MOV R3, A
06 77 //MOV A, @R3
07 1C //ADD A, #80
08 80
09 A0 //JC -> 26
10 26
11 77 //MOV A, @R3
12 11 //ADD A, R1
13 81 //MOV R1, A
14 7C //MOV A, #00
15 00
16 20 //ADDC A, R0
17 80 //MOV R0, A
18 72 //MOV A, R2
19 3C //SUB A, #01
20 01
21 A4 //JZ -> 45
22 45
23 82 //MOV R2, A
24 AC //JMP -> 02
25 02
26 77 //MOV A, @R3
27 3C //SUB A, #80
28 80
29 E4 //CPL A
30 1C //ADD A, #01
31 01
32 11 //ADD A, R1
33 81 //MOV R1, A
34 7C //MOV A, #FF
35 FF
36 20 //ADDC A, R0
37 80 //MOV R0, A
38 72 //MOV A, R2
39 3C //SUB A, #01
40 A4 //JZ -> 45
41 45
42 82 //MOV R2, A
43 AC //JMP -> 02
44 02
45 70 //MOV A, R0
46 1C //ADD A, #80
47 80
48 A0 //JC -> 52
49 52
50
51
52 70 //MOV A, R0
53 E4 //CPL A
54 80 //MOV R0, A
55 71 //MOV A, R1
56 E4 //CPL A
57 1C //ADD A, #01
58 01
59 81 //MOV R1, A
60 70 //MOV A, R0
61 2C //ADDC A, #80
62 80
63 80 //MOV R0, A
64
65
# ————-数据段————
80 19 //25 0001 1001
81 8C //-12 1000 1100
82 10 //16 0001 0000
83 26 //38 0010 0110
84 96 //-22 1001 0110
85 38 // 56 0011 1000
86 2E //46 0010 1110
87 A1 //-33 1010 0001
88 6D //109 0110 1101
89 21 //33 0010 0001

(っ•̀ω•́)っ✎⁾⁾ 坚持技术学习、内容输出与分享,您的支持将鼓励我继续创作!(*/ω\*)
( • ̀ω•́ )✧如有疑问或需要技术讨论,请留言或发邮件到 aclearzhang@qq.com.(*・ω< ) 
  • 本文作者:: AClearZhang
  • 本文链接:: 642.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!