指令寄存器

分析Android APK- smali 语言简介

社会主义新天地 提交于 2019-12-01 07:46:50
2.1 smali 语言简介 1.smali apk文件通过apktool反编译出来的都有一个smali文件夹,里面都是以.smali结尾的文件。 smali语言是Davlik的寄存器语言,语法上和汇编语言相似,Dalvik VM与JVM的最大的区别之一就是Dalvik VM是基于寄存器的。基于寄存器的意思是,在smali里的所有操作都必须经过寄存器来进行。 2.基本数据类型 B—byte C—char D—double F—float I—int S—short V—void J—long Z—boolean 注意J、Z两个不是对应类型的首字母; 在dalvik字节码中,寄存器都是32位的,能够支持任何类型,Long和Double类型是64位的,需要2个寄存器; V 只能用于返回值类型; 3.数组和对象是引用类型 数组的表示方式是在基本类型前加上前中括号“[”,例如int数组和float数组分别表示为:[I、[F; 对象类型以L作为开头来表示,格式是Lpackage/ClassName;(用分号表示对象结束是必须的),示例: String对象在smali中为:Ljava/lang/String; Class1对象的一个boolean成员表示为:Lcom/disney/Class1;->isRunning:Z Class1对象的一个String对象成员表示为:Lcom/disney

程序的机器级表示

有些话、适合烂在心里 提交于 2019-12-01 07:28:24
机器级代码 在计算机中最终执行的都是机器代码,汇编代码、C 语言代码和高级语言的代码都需要转换成机器代码来执行。文章涉及的机器语言主要指 Intel IA32。 如下一段 C 语言代码: 1 int accum = 0; 2 3 int sum(int x, int y) 4 { 5 int t = x +y; 6 accum += t; 7 return ; 8 } 通过 gcc -m32 -O1 -o code.o -c code.c 生成二进制格式的目标代码文件 code.o,通过 hexdump 查看文件内容,在计算机中最终执行的字节指令是: 通过 objdump -d code.o 反汇编查看这段二进制对应的汇编内容: 这里的指令 55 对应了汇编代码 push %ebp,汇编代码非常接近于机器代码,它用可读性更好的文本表示处理器执行的指令。 除了像上面那样通过反汇编目标文件查看对应的汇编代码,还可以通过 gcc 查看 C 编译器产生的汇编代码,如下命令会产生一个汇编文件 code.s 。 # -m32 表示用 32 位模式编译 gcc -O1 -m32 -S code.c 数据格式 虽然 C 语言可以在存储器中声明和分配各种数据类型的对象,但是机器代码只是简单地将存储器看成是一个很大的、按字节寻址的数组。C 语言中的聚合数据类型,例如数组和结构

STM32驱动ILI9341控制器控制TFTLCD显示

让人想犯罪 __ 提交于 2019-12-01 07:01:17
一、用STM32控制TFTLCD显示的编程方法, 在编程驱动TFTLCD液晶显示器之前,我们先熟悉以下概念: 1、色彩深度,这是一个与TFTLCD显存对应的概念;所谓色彩深度就是每个像素点需要多少位的RGB 数据表示该点的颜色信息。注意,不同的TFTLCD显示器的RGB的对应关系不一样,这个可以在LCD 控制芯片手册中找到答案。 例: 某LCD显示支持8、16、24位RGB,这些位数是指该像素点 颜色由 8、16、 24 位RGB构成,但是 R\G\B三种颜色各占的位数可以查看数据手册。 2、TFTLCD的操作分为两种: A、对控制寄存器的读写操作(即程序员将要操作LCD显存寄存器的地址设置成可读或者可写)。 B、对显存寄存器的读写操作(即读写LCD显存寄存器)。 3、TFTLCD有一个索引寄存器,对控制寄存器操作前,需要对索引寄存器进行定入操作,用以指明 寄存器读写是针对那个寄存器的,具体操作步骤如下: RS为低电平状态下,写入两个字节的数据,第一个字节为零,第二个字节为寄存器索引值。 RS为高电平状态下,读取两个字节数据,第一个字节为高八位,第二个字节为低八位。 二、实验平台STM32F103RCT6与ILI9341 TFTLCD驱动模块 硬件采用 16 位的并方式与外部连接,之所以不采用 8 位的方式,是因为彩屏的数据量比较大, 尤其在显示图片的时候,如果用 8 位数据线

数组分配与访问

元气小坏坏 提交于 2019-12-01 06:59:53
数组:将标量数据聚集成更大数据类型 C语言实现数组简单,容易翻译成机器代码 在机器代码中,这些指向数组元素的指针会被翻译成地址计算 优化编译器非常善于 简化数组索引所使用的地址计算 ,这使得我们难以理解C语言代码与机器代码的对应关系 一. 基本原则 一维数组的声明:T A[N](T为数据类型,N为常数) 两个效果:在内存中分配L*N字节的连续区域;引入标识符A,用A来作为指向数组开头的指针,值为x A 数组元素i会存放在x A +i*L的地方 内存引用指令 可以用来 简化数组访问 movl (%rdx, %rcx, 4), %eax 执行地址计算xA+4i,并将结果存放在寄存器%eax中 伸缩因子1, 2, 4, 8覆盖了所有数据类型的大小 知识点回顾 : 内存引用是操作数的一种 操作数 一共有 3 种: 立即数 (书写方式:‘$’后面跟一个用标准C表示法表示的整数,例如$-577,$0x1F)、 寄存器 (书写方式为寄存器的名称ra,实际上操作的是寄存器里的值R[ra],将寄存器集合看成一个数组R,用寄存器标识符作为索引)、 内存引用 (根据 计算出来的地址 Addr访问某个内存位置Mb[Addr],表示对存储在内存中地址Addr开始的b个字节值的引用) 计算地址的方式称为 寻址模式 ,具体形式为:Imm(rb, ri, s) Imm表示一个立即数,rb称为 基址寄存器

x64指令格式

人走茶凉 提交于 2019-12-01 00:28:09
引言 看了两天的x86指令集,终于基本搞懂了x64的指令格式(只是x64哦,没有特别关注16位和32位时的格式),和RISC相比实在是太复杂了,难怪x86的功耗将不下来,光是译码器就不知道得做的多么复杂。 x64指令格式 x64指令共包括七个部分,即: legacy prefix(一个字节) REX prefix(一个字节) opcode(一到三个字节) ModRM(一个字节) SIB(一个字节) disp(最多可以8个字节) imm(最多可以8个字节) legacy prefix legacy prefix在x64下应该不常用。一种情况是需要使用16位的operand时(例如 mov ax 0x1234 ),需加前缀0x66以改变 default operand size (x64下该值是32)。还有就是需要lock的情况。还有其他情况就没有细看了。 REX REX前缀非常重要,正是这个前缀将x86带入了64位模式。它的高四位一定是0x4,低四位分别代表W、R、X、B。 W:x64模式下大部分指令的 default operand size 是32位的,对这类指令,如果需要64位的操作数,将需要将W置位,例如 mov rax rbx 。 R:将 ModRM.reg 从8个扩展到16个。 X:将 SIB.index 寄存器从8个扩展到16个 B:将 SIB.base 或者

2019-2020-1 20199314 <Linux内核原理与分析>第二周作业

感情迁移 提交于 2019-11-30 16:06:02
操作系统如何工作 一、计算机的三个法宝 1.存储程序计算机 2.函数调用堆栈机制(高级语言可以实现的基础机制) 3.中断 在第一周的作业中对存储程序计算机也就是通俗意义上的冯诺依曼计算机进行了介绍。 第二周的作业中介绍了函数堆栈的结构和寄存器。在这里就不再复述。 二、汇编代码的分析(难点及问题) 本次实验中接触到的是高级语言程序编译成汇编语言的代码,其中就遇到了以下问题。 1.堆栈增长方向的问题 在之前的学习中堆栈都是向下增长的,堆栈上方是高地址下方是低地址,如左图。而在本章中图2-1,堆栈方向为了直观一点变为下方是高地址上方是低地址,如右图。 而对堆栈为什么采用向下增长产生了疑惑。明明不太直观,为什么还是选择向下增长。直到我在网上找了很多资料才找到合理解释的理由。这样设计可以使得堆和栈能够充分利用空闲的地址空间。如果栈向上涨的话,我们就必须得指定栈和堆的一个严格分界线,但这个分界线怎么确定呢?平均分?但是有的程序使用的堆空间比较多,而有的程序使用的栈空间比较多。所以就可能出现这种情况:一个程序因为栈溢出而崩溃的时候,其实它还有大量闲置的堆空间呢,但是我们却无法使用这些闲置的堆空间。所以呢,最好的办法就是让堆和栈一个向上涨,一个向下涨,这样它们就可以最大程度地共用这块剩余的地址空间,达到利用率的最大化!原文衔接如下。 http://www.cnblogs.com/Quincy

【计算机组成原理】中央处理器CPU

不问归期 提交于 2019-11-30 15:20:06
一、CPU的功能和基本结构 1、功能 当用计算机解决某个问题是,我们首先必须为他编写程序,程序是一个指令序列,这个序列明确告诉计算机应该执行什么操作,在什么地方找到用来操作的数据,一旦把程序装入内存器,就可以由计算机来自动完成取出指令和执行指令的任务。专门用来完成此项工作的计算机部件称为中央处理器,通常简称CPU。 虚线框就是CPU结构 CPU通过地址总线 数据总线来访问存储器或者输入输出端口。 ALU:执行运算 两个数一个来自缓存寄存器DR 一个来自累加器AC 运算结果暂时存放到累加器中 状态条件寄存器:0标志位 溢出标志位 等 缓冲寄存器DR:信息进出CPU都有在这蹲点,不论是指令还是数据进CPU都要先进缓存寄存器DR。 指令寄存器:当前正在执行的指令,这里的指令中包含操作码和地址码,将操作码送入指令译码器就知道指令是做什么的,指令译码器把翻译结果告诉操作控制器和时序产生器,他们再按照时间顺序向计算机的执行部件发出执行命令。 程序计数器:下一条将要执行指令的地址 地址寄存器:存放CPU正在访问的内存的地址,一般和地址总线直接相连 CPU的基本部分由运算器 cache和控制器三大部分组成。 二、指令的执行过程 1.指令周期的基本概念 问题:计算机读取的指令和数据都是存在存储器里面的二进制代码,计算机如歌区分这二进制代码是指令还是数据? 计算机能自动的工作

2019-05-16-日常零碎知识点

喜夏-厌秋 提交于 2019-11-30 12:19:57
版权声明:本文为 Jiawei Xu 于2019年5月16日所写,未经允许不得转载。 Linux网络编程 socketaddr socktaddr_in socketaddr_un UNIX Domain Socket,虽然网络socket也可以用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。Unix Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。X Window服务器和GUI程序之间就是通过UNIX Domain Socket通讯的。 使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。 UNIX Domain

一、计算机网络概论

别说谁变了你拦得住时间么 提交于 2019-11-30 07:38:27
1.计算机硬件基本组成(考点较少,了解基本组成即可,功能熟悉就行) (1)基本概述 计算机系统由硬件和软件组成。硬件由 运算器,控制器,存储器,输入输出设备 5大部件组成,这是由冯·诺依曼提出的经典计算机结构模型。 其中, 运算器和控制器 被集成在一起成为 中央处理单元-CPU 。CUP是 硬件 系统的核心,用于 数据加工处理 ,能完成各种 算数逻辑运算及控制 功能。 (2)各部件的作用如下:  控制器 :整机的指挥中心,它使计算机的各个部件自动协调工作。 运算器 :对数据信息进行处理的部件,用来进行算术运算和逻辑运算。 存储器 :存放程序和数据,是计算机实现“存储程序控制”的基础。  输入设备 :将人们熟悉的信息形式转换成计算机可以接受并识别的信息形式的设备。 输出设备 :将计算机处理的结果(二进制信息)转换成人类或其它设备可以接收和识别的信息形式的设备. (3)中央处理单元-CPU 包括运算器,控制器,寄存器组合内部总线。 1)、控制器 一般包括指令控制逻辑,时序控制逻辑,总线控制逻辑和中断控制逻辑等。 功能 (1)取指令 (2)分析指令 (3)执行指令,发出各种操作命令 (4)控制程序输入及结果输出 (5)总线管理 (6)处理异常和特殊请求 2)、运算器的功能 由算数逻辑单元、累加寄存器、数据缓冲寄存器和状态条件寄存器等组成,实现算术运算和逻辑运算

指针

こ雲淡風輕ζ 提交于 2019-11-30 06:20:01
对于学习c/c++的同学,指针是不可避免的而且也是必须掌握的 指针可以说是c/c++中很精华的一个东西 如果对于指针不了解那么这门编程语言可以是说你是不合格的 好,首先我们弄清几个问题 1.c/c++为什么要有指针这东西? 2.指针到底是个什么东西? 3.指针到底有什么用? 4.指针到底怎么用? 1.c/c++为什么要有指针这东西? 其中涉及一些硬件的东西,计算机组成原理。了解一下就好了,我也不是很懂。百度的 原文 https://blog.csdn.net/dangbai01_/article/details/79501037 早期的CPU(也许并没有真正的实现)并不如今天的强大, 内存读写的指令可能只有: “从*常数*0x1234地址处读入1字节到寄存器a”, 或者“把寄存器b的值写入*常数*地址0x5678这个地方”。 那个时候没有变量这一说,所有的内存读写都得指定好常数,也就是得把具体的数字(也称为字面量,literal)写死在程序里。 换言之,你如果想清空100字节的内存,而每条指令只能对内存中某一个字节进行写入,那就得写100条指令。随着要处理的数据的膨胀,程序也得跟着膨胀,而这是不可接受的。 流程跳转 为了解决清空大量内存的问题,人们发明了控制流程的指令 比如“如果寄存器c的值为0,则略过下一条指令”和“无条件跳转到首地址为0x9012”的地方,从那个地方继续运行”。