汇编指令

基础知识

こ雲淡風輕ζ 提交于 2019-11-30 02:44:10
机器语言 :计算机工作基于二进制,从根本上说, 计算机只能识别和接受由0和1组成的指令 ,而这种指令称为 机器指令 ;基于二进制表示的语言就是机器语言。 用法 :在机器语言的规则中规定各种机器指令的表示形式以及它的作用。( 人为规定具体机器指令的具体作用 ) 缺点 :机器语言与我们习惯的语言相差太大,难以从容使用,必须记和翻阅指令表才可以。 优点   :机器语言占内存较高级语言少、运行效率也比高级语言高,且能直接操作计算机的各种硬件设备资源。 发展 :为了克服机器语言的缺点,我们创造出了 符号语言 (symbolic language) 符号语言 : 用一些英文字母和数字表示一个指令,例如用ADD代表'加',MOV代表'移动',LD代表'传送'.....(其实就是我们日常说的汇编语言) 用法 :比如 ADD A,B 表示的是A加上B... 缺点 :前面我们说过计算机只能识别和接受0和1,而符号语言必须翻译成机器语言才可被计算机识别。翻译符号语言需要用到一种称为 汇编程序 的软件,把符号语言的指令转换为机器指令。一般,一条符号语言的指令对应转换为一条机器指令。转换的过程或者说是翻译的过程称为'汇编',因此,符号语言又称为 符号汇编语言 或 汇编语言 (assembler language) 。 虽然汇编语言比机器语言简单好记一些,但仍然比较复杂,也需要记忆基本指令集和翻阅指令集

C++编辑编译链接运行

痴心易碎 提交于 2019-11-29 21:23:52
  从写一个简单的“hello world!”到完成一个大型程序,当程序从编辑完成到执行成功都会经过5个步骤,分别是预处理(Prepressing)、编译(Compilation)、汇编(Assembly)、链接(Linking)和执行(Executing)。了解这五个过程中所做的工作,对我们理解头文件、库文件等在程序中的作用是有帮助的,而且如果能够清楚的了解编译链接过程,在编程时定位错误,纠正错误,以及编程时手动调整编译器以通过调试有很大帮助。 1.预处理 预处理器,进行预处理。预处理过程主要处理那些源代码文件以“#”开始的预编译指令。比如“#include”、“#define”和条件预编译指令,如“#if”、“#ifdef”等。预处理时,将所有的“#define”删除,展开所有的宏定义,并且替换掉“#include”。    (1)宏定义指令 ,如#define a b。对于这种伪指令,预编译所要做的是将程序中的所有a用b替换,还有#undef,则将取消对某个宏的定义,使以后该串的出现不再被替换。    (2)条件编译指令 ,如#ifdef,#ifndef,#else,#elif,#endif等。这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉。    (3) 头文件包含指令 ,如

全局描述符表GDT

烂漫一生 提交于 2019-11-29 19:42:38
写在前面 添油加醋系列第二弹——剖析GDT 头文件: https://github.com/bajdcc/MiniOS/blob/master/include/gdt.h 实现: https://github.com/bajdcc/MiniOS/blob/master/src/kernel/gdt.c 话说C语言的话除了刷刷OJ外,就是用来实现操作系统这个大头了。C语言比C++少了很多很多臃肿的语法特性,写起来非常优美(至少写操作系统是这样的)。虽说C++有许多的奇技淫巧,一个算法有N种实现方法,但这会让选择恐惧症患者(比如我)难堪,比如说一个类要怎样写啊等等,,抛开其他不谈,假如一个语言的语法特性越少,学起来可能越简单(刚试过lua语法很简单)。OK废话不多说,进入本章主题(涉及OS的资料很杂很偏,如有错误望海涵)。 GDT的构成 这个网址不错(英文的): Global Descriptor Table 首先,根据网上资料,GDT(全局描述符表)又叫段描述符表,暂且就这样认为吧,如有异议可以提出来。 一个GDT可能是这样的( GDT与LDT - Lan'Sir - 博客频道 - CSDN.NET ): 同样也是这样的( Global Descriptor Table ): 在代码中它又是这样: // 全局描述符表结构 http://www.cnblogs.com

第十二章 Java内存模型与线程

▼魔方 西西 提交于 2019-11-29 19:11:47
概述 并发应用场景:①充分利用计算机处理器的能力;②一个服务端同时为多个客户端提供服务。 衡量一个服务性能的高低好坏,每秒事务处理数是最重要的指标之一。 硬件的效率与一致性 Java内存模型 主内存和工作内存 ①Java内存模型的主要目标是定义程序中各个变量的访问规则 – 虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。此处的变量(Variables)包括了实例字段、静态字段和构成数组对象的元素,但不包括局部变量与方法参数,因为后者是线程私有的,不会被共享,自然就不会存在竞争问题。 ②Java内存模型并没有限制执行引擎使用处理器的特定寄存器或缓存来和主内存进行交互,也没有限制即时编译器进行调整代码执行顺序这类优化措施。 ③Java内存模型规定了所有的变量都存储在主内存(Main Memory,类比物理内存)。每条线程还有自己的工作内存(Working Memory,类比处理器高速缓存),线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝。线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成,线程、主内存、工作内存三者的交互关系如图所示。 内存间相互操作 一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的实现细节

汇编(三)——关于寄存器的操作

帅比萌擦擦* 提交于 2019-11-29 12:43:21
目录 汇编(三) 一、通用寄存器 二、加深对AX、BX、CX、DX印象 三、监测点2.1 四、地址寄存器 五、监测点2.2 六、CPU如何区分指令与数据 七、加深CPU如何区分指令和数据印象 八、IP寄存器和指令的关系 汇编(三) 一、通用寄存器 AX、BX、CX、DX 1 byte = 8 bit 2 byte = 16 bit 0000 0000 0000 0000 ~ 1111 1111 1111 11111 他们可以各自分为2个8位寄存器 AX = AH*AL BX = BH*BL CX = CH *CL DX = DH*DL 为什么存在通用寄存器? 1.因为为了兼容之前的8位寄存器,保证之前的程序,稍加修改就可以运行在8086CPU上 2.内存最小单元 8 bit CPU从内存中读取一个字节 8 bit字节的数据 8位数据 -> 8位寄存器中 16根数据线 8086CPU一次性可以处理 2种尺寸的数据 字节型数据 byte 8bit 8位寄存器中 字型数据 2byte 16bit 16位寄存器中 2个字节 一个字节是高位数据,一个是低位 二、加深对AX、BX、CX、DX印象 mov ax,5 mov ax,0 mov al,5 按下r查询,按下t执行 分析下面命令 mov ax,4E20 mov bx,ax mov ch,bl mov cl,bh mov dl,ch

网易互娱我来辣

岁酱吖の 提交于 2019-11-29 12:32:55
static的作用: 1.第一条也是最重要的一条:隐藏 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。如果加了static,就会对其它源文件隐藏。例如在a和msg的定义前加上static,main.c就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。Static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏 2.static的第二个作用是保持变量内容的持久 3.static的第三个作用是默认初始化为0 虚函数,具体怎么实现 https://blog.csdn.net/weixin_40237626/article/details/82313339 指针和引用的区别: 内存分配: 指针是一个实体,需要分配内存空间。引用只是变量的别名,不需要分配内存空间。 初始化: 引用在定义的时候必须进行初始化 , 并且不能够改变。 指针在定义的时候 不一定要初始化 , 并且指向的空间可变。 使用级别:有多级指针,但是没有多级引用,只能一级引用。 自增运算:指针和引用的自增运算结果不一样。(指针是指向下一个空间,引用时引用的变量值加1) 使用sizeof时: 引用得到的是所指向的变量(对象)的大小,而sizeof 指针得到的是指针本身的大小。 直接与间接访问: 引用访问一个变量是直接访问

ARM汇编指令集

亡梦爱人 提交于 2019-11-29 12:19:22
跳转指令 B BL会把当前PC指针的值加4保存到R14里。 MOV{条件}{S} 目的寄存器 ,源操作数 只能用在通用寄存器的操作 MOV R1,R0 将寄存器R0的值传送到R1里 MVN{条件}{S} 目的寄存器 ,源操作数 在传送之前按位取反,即把一个被取反的值传送到目的 寄存器中。 S决定指令操作是否影响CPSR中条件标志位的值,没有S 时指令不更新CPSR中条件标志位的值。 CMP{条件}操作数1,操作数2 把两个操作数进行比较,同时更新CPSR中条件标志位的值 该指令进行一次减法运算,不存储结果,只更改条件标志位 TST{条件 }操作数1,操作数2 把一个寄存器的内容和另一个寄存器的内存或立即数进行按位与运算,并 更新CPSR中条件标志位的值,当位与结果为0时,EQ位被设置。 TST R5,#(1<<23) ;当bit23位为1时,CPSR EQ位被设置 ADD{条件}{S}目的寄存器,操作数1,操作数2 将两个操作数相加,把结果放在目的寄存器中。 ;ADD指令 MOV R1,#1 MOV R2,#2 MOV R3,#3 ADD R0,R1,R2 ;R0=R1+R2 ADD R0,R1,#256 ;R0=R1+256 ADD R0,R2,R3,LSL#1 ;R0=R2+(R3<<1) SUB{条件}{S}目的寄存器,操作数1,操作数2 用操作数1减操作数2

深入浅出计算机组成原理:Superscalar和VLIW-如何让CPU的吞吐率超过1?(第26讲)

不想你离开。 提交于 2019-11-29 03:10:51
一、引子 到今天为止,专栏已经过半了。过去的20多讲里,我给你讲的内容,很多都是围绕着怎么提升CPU的性能这个问题展开的。我们先回顾一下第4讲,不知道你是否还记得这个公式: 程序的CPU执行时间 = 指令数 × CPI × Clock Cycle Time 这个公式里,有一个叫CPI的指标。我们知道,CPI的倒数,又叫作IPC(Instruction Per Clock),也就是一个时钟周期里面能够执行的指令数,代表了CPU的吞吐率。那么,这个指标,放在我们前面几节反复优化流 水线架构的CPU里,能达到多少呢? 答案是,最佳情况下,IPC也只能到1。因为无论做了哪些流水线层面的优化,即使做到了指令执行层面的乱 这说明,无论指令后续能优化得多好,一个时钟周期也只能执行完这样一条指令,CPI只能是1。但是,我们现在用的Intel CPU或者ARM的CPU,一般的CPI都能做到2以上,这是怎么做到的呢? 今天,我们就一起来看看,现代CPU都使用了什么 “黑科技”。 二、多发射与超标量:同一实践执行的两条指令 1、整数和浮点数计算的电路,在CPU层面也是分开的 之前讲CPU的硬件组成的时候,我们把所有算术和逻辑运算都抽象出来,变成了一个ALU这样的“黑盒子”。你应该还记得第13讲到第16讲,关于加法器、乘法器、乃至浮点数计算的部分,其实整数的计算和 浮点数的计算过程差异还是不小的。实际上

深入浅出计算机组成原理:冒险和预测(四)-今天下雨了,明天还会下雨么?(第24讲)

让人想犯罪 __ 提交于 2019-11-29 01:47:32
一、引子 1、取指令(IF)和指令译码(ID)的阶段,是不需要停顿的 过去三讲,我主要为你介绍了结构冒险和数据冒险,以及增加资源、流水线停顿、操作数前推、乱序执行,这些解决各种“冒险”的技术方案。 在结构冒险和数据冒险中,你会发现,所有的流水线停顿操作都要从 指令执行阶 段开始。流水线的前两个阶段,也就是取指令(IF)和指令译码(ID)的阶段,是不需要停顿的。CPU 会在流水线里面直接去取下一条指令,然后进行译码。 2、一旦遇到 if…else 这样的条件分支,或者 for/while 循环就会不成立 取指令和指令译码不会需要遇到任何停顿,这是基于一个假设。这个假设就是,所有的指令代码都是顺序加载执行的。不过这个假设,在执行的代码中,一旦遇到 if…else 这样的条件分支, 或者 for/while 循环,就会不成立。 我们先来回顾一下,第6讲里讲的cmp比较指令、jmp和jle这样的条件跳转指令。可以看到,在jmp指令发生的时候,CPU可能会跳转去执行其他指令。jmp后的那一条指令是否应该顺序加载执行, 在流水线里面进行取指令的时候,我们没法知道。要等jmp指令执行完成,去更新了PC寄存器之后,我们才能知道,是否执行下一条指令,还是跳转到另外一个内存地址,去取别的指令 3、如何解决停顿 这种为了确保能取到正确的指令,而不得不进行等待延迟的情况,就是今天我们要讲的 控制冒险

汇编语言 实验1

孤街浪徒 提交于 2019-11-28 22:50:53
实验1 一、熟悉debug功能 : -r 查看/修改寄存器内容 用法1: -r 查看当前各寄存器中内容 用法2: -r 段地址:偏移地址 修改【段地址:偏移地址】表示的内存中的内容 示例: -d :查看内存中的内容(右侧显示以内存中的内容作为ASCLL码的符号,如果没有对应符号则显示“.“) 用法1: -d 查看从当前CS:IP地址开始的默认128字节内容 用法2: -d 段地址:偏移地址 查看从【段地址:偏移地址】表示的内存开始的默认128字节内容 用法3: -d 段地址:偏移地址1 偏移地址2(或l+数字) 查看从【段地址:偏移地址1】表示的内存开始到偏移地址2的内容(或者显示指定长度的内容) 示例: -e :改写内存中内容(后面一定要加地址,否则报错) 用法1: -e 【段地址:偏移地址】 要改写的内容(用空格间隔) 从【段地址:偏移地址】开始改写内存中的内容,最多能一次性输入32个左右 用法2: -e ‘字符’ ‘字符’ ……(或者“字符“) 从【段地址:偏移地址】开始改写内存中的内容,以ASCLL码的方式存入内存单元 用法3: -e 【段地址:偏移地址】 可以逐个修改从【段地址:偏移地址】开始内存中的内容,形式为“原值.修改值“,(原值会自动给出)按空格进入下一个值得修改。若原值不需要修改,则按空格跳过。 示例: 单步跟踪指令 -t :执行一条指令。遇到loop