汇编语言 linux 终端 设置光标位置(汇编语言 linux)-编程知识网

汇编语言是一种什么语言好学吗?

汇编语言是面向机器的语言,而不是机器语言。机器语言和汇编语言都是最低级的编程语言,面向机器,但最最低级的还是费解的机器语言:0和1。汇编语言的创造是因为在早期人们长期与计算机痛苦地交流之后随着对机器语言和自然语言、数学语言结合的强烈渴望,开始用一些例如ADD、MOV这样的单词表示一些操作,汇编语言可以直接操控硬件,是面向机器的低级语言,效率相当高,功能相当强,想学精通比较不易,C语言、C++、JAVA、C#、VB这些语言是面向过程和面向对象的高级语言,是汇编语言的小弟,效率更低,更好学,可移植性更好,不直接面向机器。

一般的大型软件(例如腾讯QQ和迅雷)使用C++等语言编写,很多热门应用和程序使用JAVA等语言制作,例如Windows和Linux这样的操作系统使用汇编语言和C语言结合编写。请那些什么机器语言啦、最低级的语言(你不知道还有个机器语言顶着呢么)的人自重!

cmd支持什么语言?

准确的说cmd并不是某一种语言,无论是WINDOWS系统,百还是LINUX 系统,每种系统都有着各自的图形窗口状态,而命令行状态只是操作系统下的一种状态。这种状态(cmd命令)可以是由C语言编写的、也可以是由汇编语言编写的。

汇编语言是一种什么语言?

结合本人从清华学习经验,说说本人的深切体会吧,初识它时,认为汇编语言是一种助记符,一种低级语言,直接面对指令,将二进制指令替换成人类便于记忆的字符串,并冠以特殊的格式。每一条汇编指令对应一条二进制指令。根据内核架构的不同,不同的指令有不同的长度和格式。

大多数人一开始都以为汇编语言本身很简单,常用指令没几个,语法规则也不多,看几个小时资料似乎就明白了,但其实不然。汇编的背后是体系结构,是程序设计抛开各种高层形态的最根本,最本质的解释。本人从业多年,除了跟我一样搞过很久安全的同学,其余的没有一个我认为算是精通汇编。而我是怎么掌握汇编的呢 ?

1 早年用汇编手写病毒。比如处理指令重定位,是真的用汇编计算指令地址,push push call 实现函数调用。

2 长期病毒木马二进制分析。分析明白各种 malware 的原理,实现查杀防。个别病毒,需要实现修复。

3 漏洞挖掘。fuzzer 发现漏洞,汇编级详细分析,exploit 编写,武器化利用,一条龙。

4 各种逆向分析。好的东西没有代码,IDA 里看就是了。

5 跟debuger 做朋友。从来看不上print 方式的bug定位。所有问题在调试器里分析明白,绝不靠猜。

6 编译器后端研究。什么指令选择,指令调度,寄存器分配,全都研究一遍。

7 底层开发,操作系统,设备驱动,虚拟化都走上一遍。X86很熟? ARM学一遍做对比。历经这么多,终于敢说学明白汇编了。推荐如下的文档,很基础又相对全面的介绍了很多计算机常见问题在汇编层面的解释。《Introduction to Computer Organization with x86-64 Assembly Language & GNU/Linux》

学汇编不是说一定要用这它做多牛鼻的事情, 问题的关键在于, 学透了汇编会使你真正理解计算机另外一方面, 如上面所说, 在工作中你迟早会在某个阴暗的角落遇到汇编. 不管你承认不承认, 现在的CPU没有直接跑高级语言的, 哪怕是虚拟机也都是类似汇编的指令集.当遇到崩溃分析, 性能优化甚至编译器抽风等等的时候, 汇编是你最后一根救命稻草.

下面再讲讲汇编语言的基本内容吧:

目前国内的汇编语言教材大多都是上来先讲一大堆CPU、总线、寄存器、标志位……再讲汇编语言程序设计。这种字典式的编写方法对入门是很不利的,因为在不知道这些东西都是用来干什么的情况下,全部记忆往往很难。然而这些概念在编程中还不得不用到,于是又得重新往前翻书,这就陷入了一个循环。

实际上,汇编语言的学习完全可以和高级语言一样。只不过因为汇编语言是根据CPU的工作原理进行操作,所以一切代码都要从CPU和内存的角度考虑问题。理解了指令在内存层面的执行过程,编程就水到渠成了。

先从最简单的开始:给定两个数a和b,让CPU做一次加法,结果储存在c中。输出c。

用C语言编写这个程序:

int a=3;

int b=4;

int c;

int main()

{

c=a+b;

printf(“%d”,c);

return 0;

}

(注意:如果写int c=3+4,一行就可以搞定。但是这里没这样做,而是先统一声明所有的变量,然后再在进行运算的主函数中执行相加操作。后面可以看到,这种编程习惯是符合二进制数据在内存中的存放规律的。)

如果用汇编语言编写,该怎样写呢?

再重复一下题目:给定两个数a和b,让CPU做一次加法,结果储存在c中。输出c。

要从原理上写这个过程,就要解决以下问题:

①数据a和b怎么存储 ②怎么做加法 ③怎么储存结果 ④怎么输出结果

下面将分别解决这四个问题。

1.汇编语言程序的结构

首先,我们要知道二进制信号在内存中的存放规律。众所周知,计算机能直接处理的只能是二进制信号,这些信号以高低电平的方式存放在内存中,既可以作为指令,也可以作为程序使用的数据。一块内存区域所存放的二进制信号到底是指令还是数据,是由相应的命令说了算的。

CPU在读取指令/数据时,每读取一条指令/数据,内存位置指针就加1,指向下一条指令/数据的内存地址。这样就产生了一个问题:数据和指令在内存中应该分块,并且要连续存放。否则如果内存位置指针不知道下一个位置是数据还是代码,将会给内存位置指针的寻址带来极大的不便。所以,在汇编程序中,要人工将内存分为数据段(Data Segment),代码段(Code Segment),堆栈段(Stack Segment)和附加段(Extra Segment)。

这样划分好以后,我们只需要告诉内存位置指针每个段在内存中的起始地址,内存位置指针就可以顺利寻址了。怎样告诉呢?在CPU中,有一组专门的段寄存器用来存放各个段的起始地址。它们是:DS(用来存放数据段的起始地址),CS(用来存放代码段的起始地址),SS(用来存放堆栈段的起始地址),ES(用来存放附加段的起始地址)。程序员在编程时,需要人工指定这些段寄存器对应于程序中的哪个段。

有了段的概念,我们就可以写出一个汇编程序的基本框架如下:

DATA SEGMENT ;定义一个叫DATA的段。DATA既是这个段的名称,也指代这个段的地址。但这里并未规定这个段是数据段、代码段还是其他段

……

SEGMENT ENDS ;表示段结束。ENDS是END SEGMENT的缩写。

STACK SEGMENT ;定义一个叫STACK的段,这个段的地址用STACK表示。

……

SEGMENT ENDS ;段结束

CODE SEGMENT ;定义一个叫CODE的段,,这个段的地址用CODE表示。

ASSUME:CS:CODE,DS:DATA,SS:SEGMENT ;告诉编译器,将代码中写的各段分别对应上各个段寄存器。这句话要放在准备用作代码段的段开头

……

SEGMENT ENDS ;段结束

好了。回到我们的问题:怎样存储a和b呢?在数据段中声明变量如下:

DATA SEGMENT

A DW 03H ;定义一个名为A的双字节(即1个字)的数据,DW是Define Word 的缩写。末尾加H表示十六进制。

这相当于C语言中的int A=3,只不过int表示的范围远大于DW而 已。

B DW 04H ;定义一个名为B的双字节数据。由于B是紧挨着A之后定义的,根据 数据段的连续性,B在数据段的偏移地址就是A在数据段的偏移地 址 + A的长度。由于 A是双字节数据,所以A的长度是2个字。

SEGMENT ENDS

2.CPU的运算方式及运算结果的判定

第二个问题:怎样做一次加法?

CPU只能处理电平信号。学过模电的都知道,有一种东西叫“加法器”,输入2个电压信号,经过运算放大器后,就会得到这两个信号的和。所以CPU做加法的方式就是:把输入的两个二进制信号输入加法器,得到结果。

问题似乎解决了。但是我们突然发现,这样的结果几乎没有任何意义,因为我们无法知道结果的性质。比如,如果结果超出了能容许的最大位数(溢出),会怎么样?CPU没有任何提示。又或者,我们要比较两个数的大小,这就要将两个数相减。然而结果是正是负?我们无从知晓。

为了获知运算结果的性质,在CPU中设置了一个“标志寄存器”,专门用于存放运算结果的各种标志。它们都是用电路实现的。比如:

CF(Carry Flag)就是用来标志无符号数运算是否产生进位。产生进位时,CF=1,反之CF=0。特别指出,CF标志位的值对有符号数的运算没有意义。

OF(Overflow Flag)则是用来标志有符号数运算是否产生溢出。产生溢出时,OF=1,反之OF=0。同理,OF标志位的值对无符号数的运算没有意义。

SF(Sign Flag)用来标志结果的正负。当结果是负(SF)时,SF=1。反之SF=0。

回到我们的问题:怎么做一次加法?或者更一般地,怎样做一次运算?

我们不必关心具体的电路实现细节,只需要执行相应的运算指令,运算完成后,不仅会得到结果,各个标志位的值也可能发生相应的改变,从而有利于我们对结果的判断。例如:

ADD AX,BX ;把AX和BX中的内容相加,结果存放在AX中。若AX,BX为有符号数,当 产生溢出时,OF=1.CF的值不确定。当结果为负时,SF=1。

3.内存与寄存器的关系

内存(RAM)是存放各种数据、指令的地方。根据用途的不同,又可以把它分成不同的段。而寄存器(Register)则是CPU内部临时存放运算结果的地方。与容量较大的内存相比,寄存器的容量极小(每个寄存器只有16位),数量有限(只有少数几个),用途专一(各个寄存器有不同的用途,用来存放不同方面的结果)。例如,前面所述的段寄存器(DS,CS,SS,ES)就是用来存放段的起始地址的。除了段寄存器之外,CPU中还设有通用寄存器(AX,BX,CX,DX……)。它们各自有其专门的用途,在不致于产生冲突的情况下,也可以用来存放数据或运算结果。

通用寄存器的用途简述如下:(通用寄存器容量都是16位的)

AX:①用来存放数据或运算结果

②AX的高8位AH用于与DOS操作系统通信。向AH中装入DOS系统的指令码并执行,可以利用DOS系统完成一些操作,如在屏幕上输出字符。

DX:①用来存放数据或运算结果

②与AH的DOS屏幕输出指令码配合使用,存放准备输出到屏幕上的数据

CX:在有循环的程序中,用来存放循环次数。相当于for循环中的计数变量i。

BX、SI、DI:①用来存放数据或运算结果

②用来存放数据段中的数据在段中的偏移地址

一般而言,需要运算的数据存放在内存中。CPU在程序的指令下,通过指针确定它们的位置,将它们读入寄存器。进行运算后,再将结果返回到内存预留的结果位置中。

回到我们的问题,在内存的DATA SEGMENT中存放有两个双字节数据A=3和B=4。要将它们读入寄存器进行相加运算,再将结果写入到内存中。为了读入寄存器,首先需要获取A和B在内存数据段中的偏移地址。确定它们的地址后,按地址将它们读入寄存器(这里可以任选两个寄存器),然后执行运算指令。运算完成后,将储存在寄存器中的结果写入到内存DATA SEGMENT中事先预留的位置。使用”MOV 目标,源”指令完成源对目标的赋值。代码如下:

DATA SEGMENT

A DW 03H

B DW 04H

C DW ? ;?表示声明时不赋值。相当于int c;

SEGMENT ENDS

STACK SEGMENT

SEGMENT ENDS

CODE SEGMENT

ASSUME:CS:CODE,DS:DATA,SS:SEGMENT

START: ;指定程序的入口位置(这个位置当然要在代码段中啦),并命名为START。

MOV AX,DATA

MOV DS,AX ;这两行的意思是,以通用寄存器AX为中介,将数据段DATA的起始地址(用句柄DATA表示)送入数据段寄存器DS中。在需要使用数据段的程序中,这一步是必须的,否则CPU无法确定数据段的位置。注意:ASSUME是一个伪代码,它只是告诉了编译器各个段与段寄存器的对应关系,并未存入各段的地址。(由于电路结构的原因,AX不能直接对DS赋值。不能直接写MOV DS,DATA。)

LEA SI,A ; 注意:与DATA SEGMENT中DATA的含义不同,数据段中A DW 03H中的A仅表示变量名,不表示变量的地址。类似于int a=3,a只是名称,取地址要用&a。在汇编中,取地址用LEA BX/SI/DI,A的格式。注:通常用BX、SI、DI这三个寄存器存数据的偏移地址。

MOV AX, ;将 送入通用寄存器 AX中。这里AX也可以换成BX,CX等。

INC SI ;SI的值加1。即SI++。

INC SI ;因为A是双字节数据,所以SI要加2才能指向下一个数据B的偏移地址。当 然,这两条也可用 LEA SI,B替代。

MOV BX, ;将 ——就是B,送入通用寄存器 BX中。

ADD BX,AX ;BX与AX相加,结果存放在BX中。当然也可以写ADD AX,BX。但之所以不 存放在AX中,是因为一会输出要用到AH,避免冲突。

LEA DI,C

MOV ,BX ;这两条是将存放在BX中的结果写回数据段中C所在位置

MOV DX,BX ;准备在屏幕上输出结果。屏幕输出的是寄存器DX中的内容。

ADD DX,30H ;由于屏幕上输出的是文字,因此必须将数字+30H转换为对应的ASCII码

MOV AH,02H ;将控制DOS系统输出数值的代码02H装入AH。这步可理解为printf()中的”%d”

INT 21H ;INT=Interrupt,中断,执行DOS命令。执行后返回程序。

MOV AH,4CH ;4CH是程序结束,返回DOS系统的命令。将此命令装入AH,等待执行。

INT 21H ;中断,DOS系统执行4CH命令。程序结束。这两步类似于 “return 0”

SEGMENT ENDS

END START ;在程序的尾部,告诉MASM(宏汇编)编译器程序的入口位置在标号START处运行结果如下:

汇编语言 linux 终端 设置光标位置(汇编语言 linux)-编程知识网输出结果为7。当然,你可以不用MASM编译工具,而用其它的汇编IDE集成开发环境.

最后,希望通过这篇短文,能够帮助你能更好的认识,理解,学习好这门语言。