文档库 最新最全的文档下载
当前位置:文档库 › PowerPC 汇编入门与优化

PowerPC 汇编入门与优化

PowerPC 汇编入门与优化
PowerPC 汇编入门与优化

PowerPC Figure – PPC入门与优化

By Skywind(2007)

https://www.wendangku.net/doc/ab2063181.html,/blog/

背景介绍

PowerPC于1991年IBM/MOTO/APPLE研制,大量应用于服务器(AIX / AS400系列及苹果系列服务器),家用游戏机(PS3, Wii, XBOX, GameCube),以及嵌入式(仅次于Arm/x86排第三)。PowerPC核心在于开放系统软件标准,其应用范围仅次于x86,是除去x86外最值得开发者了解的体系。

不需要写出非常高效的代码,但要了解基本效率原则;不需要大规模开发PPC程序,但需要时能写几段、调试时能看懂哪里错了。本文将从对比x86入手,引入RISC及PowerPC体系概念,向读者介绍该体系指令集,常用优化方法和交叉编译环境及模拟器的搭建等内容。

PowerPC基础知识

1990年IBM时任总裁Kuehler说服了摩托罗拉公司和苹果公司与IBM公司共同参与制订PowerPC体系结构。为了让AS/400也成为其中一员,1991 / 1992年罗彻斯特实验室开始为AS/400扩充并制订PowerPC的64位结构。

----《罗彻斯特城堡》

大部分CPU指令集都可以分为:数据读写、数值计算、流程控制与设备管理四个部分,其中设备管理不属于介绍范围。开放系统软件标准在于硬件/软件只要符合该标准都能在PowerPC下运行,也就是说先今有大量CPU虽然实现不一,但是他们在标准上都支持了PowerPC体系,使得开发与接口更为方便。

PPC使用RISC(精简指令集),指令字长都是32bit,一条Intel指令往往可以由多条PPC 指令组合表示。Endian一般都是可调的,默认使用BE(Big Endian),同时PPC没有栈,也就是说应用程序需要自己实现相关操作。

常用术语介绍

POWERPC 字长简称X86

BYTE 8 BITS B BYTE

HALF WORD 16 BITS H WORD

WORD 32 BITS W DWORD DWORD

64 BITS

D

QWORD

PowerPC 其他名称

X86 其他名称

Branch JUMP CR+SPR

EFLAGS

常用寄存器

类 别

说 明

补 充

通用寄存器 GPRs R0 - R31 各32bit

PPC64 中是64bit 相当于 EAX / EBX / ECX 条件寄存器 CR CR 32bit 被分为8段 每段4位:LT,GT,EQ, SO CR0-CR7 各4位组成 CR 相关运算需指明 CRn

连接寄存器 LR

用作记录跳转地址32bit PPC64 中是64bit

常用作记录子程序返回的地址 子程序调用指令在跳转前会改写 特殊寄存器 XER 记录溢出和进位标志 作为CR 的补充 计数器 CTR

32bit (PPC64中是64bit)

相当于 ECX 用途

浮点寄存器 FPRs FPR0 - FPR31 各64bit PPC32/PPC64的浮点都是64位 浮点状态 FPSCR 浮点运算类型和异常等

同时可设置浮点异常捕获掩码

问题1:如何加载32位立即数位立即数??

在PPC 下如何加载32位的立即数呢?RISC 下PPC 的每条指令都是4个字节定长。除去指令与寄存器参数编码,只有剩下16bit 的长度用来描述立即数,比如立即数加载指令 LI :

LI rD, SIMM

立即数SIMM 字段仅16位,如何表示32位?

答案:只有分两次载如,使用LIS (立即数载入并左移)和ADDI (立即数加法)分两次加载。因此32bit 的立即数加载需要分两次完成: LIS R3, 0x1122 加载并左移16位 ADDI R3, R3, 0x3344 再加上低16位

两条指令后,R3完成对 0x11223344的加载

特性特性::不一样的子程序调用

? f1: 子程序入口

? blr 返回(跳转到LR 地址) ? start:

? bl f1 调用f1(跳转并保存地址到LR ) ? li r1, 1 设置r1 = 1 ? li r3, 1 设置r3 = 1

?

sc

系统调用:结束程序

PPC 使用了LR 寄存器(Link Register )来完成:在bl 指令跳转前,下条指令(li r1,1)的地址会被保存到LR 而执行到f1中的blr 时,系统会跳转到LR 所表示的地址,完成返回。

数据读写指令

说明

POWERPC

说 明

X86 参考

加载 LBZ R3, 0(R2) LHZ R3, 10(R2)

LWZ R3, 32(R2) 读字节 R3<-(R2) 读半字 R3<-(R2+10) 读单字 R3<-(R2+32) MOV AL,[EBX] MOV AX,[EBX+10] MOV EAX,[EBX+32] 保存 STB R3, 0(R2) STH R3, 10(R2)

STW R3, 32(R2) 写字节 R3->(R2) 写半字 R3->(R2+10) 写单字 R3->(R2+32) MOV [EBX], AL MOV [EBX+10], AX MOV [EBX+32], EAX 赋值 LIS R3, 0, 1122h ADDI R3, R3, 34h R3 = 1122h << 16 R3 = R3 + 34h MOV EAX,11220034h 转移

OR R3, R10, R10 (别名MR R3, R10)

R3 = R10 or R10 R3 = R10

MOV EAX, ECX

注意:LBZ R3, 0(R2)与LHZ R3,10(R2)并不全等同于MOV AL,[EBX]和MOV AX,[EBX+10]。前者将字节和半字加载到R3时顺便清空了高位,而后两条指令加载数据到EAX 并不会清空高位。

第一个程序第一个程序::Hello World !!

把下面的程序保存成 hello.s ,并交叉编译: # powerpc-eabi-as -gstabs hello.s -o hello.o # powerpc-eabi-ld hello.o -o hello

? .global _start /* 请将本程序保存成 hello.s */ ? .data /* 后面将讲解如何在虚拟机中调试 */ ? msg: .asciz "Hello, PowerPC World !!\n" ? len = . - msg ? .text /* 代码部分开始 */ ? _start:

? li %r0, 4 /* r0 = 4 */ ? li %r3, 1 /* r3 = 1 */

? lis %r4, msg@ha /* r4 = msg(high) << 16 */

? addi %r4, %r4, msg@l /* r4 = r4 + msg(low) */ ? li %r5, len /* r5 = len */

? sc /* system call (print) */ ? li %r0, 1 /* r0 = 1 */ ? li %r3, 1 /* r3 = 1 */

? sc /* system call (exit) */

完成交叉编译后用 qemu 模拟器执行: # qemu-ppc hello

Hello, PowerPC World !!

关于如何在x86环境下交叉编译与调试,详细见第三部分的的“PowerPC 编译调试”。

特殊寄存器操作

类 别 指 令

说 明

mflr rD rD <- LR (等同于 mfspr rD, 8 ) 连接寄存器

mtlr rD LR <- rD (等同于 mtspr 8, rD ) 时间寄存器 mftb rD, TBR 读取 PowerPC 内置的计时器到寄存器 mfcr rD rD <- CR 条件寄存器

mtcr rD

CR <- rD

crand crbD, crbA, crbB

crbD <- (crbA) AND (crbB) cror crbD, crbA, crbB crbD <- (crbA) AND (crbB) CR 运算

creqv crbD, crbA, crbB

crbD <- (crbA) == (crbB) mfmsr rD rD <- Machine State Register 状态寄存器

mtmsr rD

MSR <- rD

问题2:没有栈仅靠LR 如何递归如何递归??

? f1: ? mflr r2 保存LR 中记录的地址到r2 ? stw r2, -8(r1) 记录r2的数值到MEM[r1-8]处 ? addi r1, r1, -60 r1后移60个字节,完成进栈操作 ? ….

? addi r1, r1, 60 r1前移60个字节,准备出栈 ? lwz r2, -8(r1) 读出老的LR 值到r2 ? mtfr r2 将r2的内容复制到LR ? blr

返回(跳转到LR 地址) ? start: ?

….

? bl f1 调用f1(跳转并保存地址到LR )

? ….

虽然PPC 没有直接提供栈相关指令(PUSH/POP/CALL/RET ),应用程序却常用R1来模拟栈指针,实现多层调用时对LR 的记录与恢复。

数值计算指令

说明 POWERPC

说 明

基础

ADD R3, R4, R5 SUBF R3, R4, R5 MULLW R3, R4, R5 DIVW R3, R4, R5 R3 = R4 + R5

R3 = (Not R4) + R5 + 1 = R5 – R4 R3 = R4 x R5 R3 = R4 / R5

标志

ADD. R3, R4, R5 SUBF. R3, R4, R5 MULLW. R3, R4, R5 DIVW. R3, R4, R5 注意指令下标“.”,代表影响条件寄存器RC0:LT, GT, EQ, SO (小于,大于,等于,益出)的状态。 逻辑

AND R3, R4, R5 OR R3, R4, R5 NOR R3, R4, R5 XOR R3, R4, R5

R3 = R4 AND R5 R3 = R4 OR R5

R3 = Not (R4 OR R5) R3 = R4 XOR R5

特性特性::RISC 的“加载/存储”体系

RISC 决定了PowerPC 使用加载/存储体系,即所有计算都是在寄存器中完成,而不是在主存中。除去加载/存储指令,所有操作都是针对寄存器的(少部分立即数),执行消耗周期相同且无须访问主存。

CISC 体系(如x86)几乎所有操作都可对内存、寄存器或两者同时进行操作。传统上,处理器被设计成适应更加复杂的指令。

RISC 是基于 “最简单的计算机指令是最经常被执行的” 这一研究基础。用简单指令的组合来执行复杂的指令。这样处理器的时间安排能以较简单和快速运算为基础,能在给定时钟速度下执行较多指令。

现代的CISC 处理器将自己的指令转换成了内部使用RISC 格式,以实现更高的效率。

PowerPC 流程控制

IBM 公司70年代首次开发RISC ,但知道多年以后才应用到IBM 公司的系统中。尽管第一款IBM RISC 处理器早在1986年就被应用到 IBM PC-RT 中,但直道 IBM 1990年推出RS/6000服务器时,该技术才开始受到重视。 -- 《罗彻斯特城堡》

条件寄存器

CR (Condition Register )一共32位,从低位到高位被分成 CR0-CR7八段,每段四位。每个四位的CRn 从低到高分别是:LT (小于标志)、GT (大于)、EQ (等于)和SO (溢出)比较指令或条件跳转指令均可指明具体操作哪个 CRn ,由此可以同时判断多个条件。整数计算默认更改CR0,浮点数计算默认更改CR1。

举例举例::求绝对值

? _ABS:

? cmpwi %r3, 0

/* 参数R3与0比较 */ ? bgt greater_than /* 如大于就跳转 */

? neg %r3, %r3

/* 取负值: R3 = Not(R3) + 1 */ ? greater_than: ? blr /* 返回 (从LR 取出地址并跳转) */ ? _start:

? li %r3, 123 /* 加载立即数 123 */

? bl _ABS

/* 调用 _ABS (跳转前记录地址到LR )*/ ? li %r0, 1 ? li %r3, 1 ?

sc /* 系统调用:结束程序 */

比较:cmpw rA, rB (比较有符号),cmpwi rA, IMM (立即数比较),cmpwl rA, rB (无符号)。 跳转:blt addr (小于跳转),bgt addr (大于跳转),beq addr (等于跳转) 类似:bne (不等),ble (小于等于),bge (大于等于)

数据比较指令

名 称

助记符 语法格式

有符号立即数比较 cmpi crfD, L, rA, SIMM 有符号数比较 cmp crfD, L, rA, rB 无符号立即数比较 cmpli crfD, L, rA, UIMM 无符号数比较

cmpl

crfD, L, rA, rB

有符号立即数字比较 cmpwi crfD, rA, SIMM (同cmpi crfD, 0, rA, SIMM) 有符号数字比较 cmpw crfD, rA, rB (同cmp crfD, 0, rA, rB)

无符号立即数字比较 cmplwi

crfD, rA, UIMM (同 cmpli crfD, 0, rA, UIMM) 无符号数字比较

cmplw

crfD, rA, rB (同 cmpl crfD, 0, rA, rB)

特性特性::多条件寄存器

判断相同 - 老代码: cmpw r3, r4

beq _branch_1 判断相同 - 新代码: cmpw cr4, r3, r4 beq cr4, _branch_1

可以在比较和跳转命令第一个参数指明所使用的条件寄存器,如果不写的话,默认 CR0。由此我们可以用更多条件寄存器同时判断若干条件,再用cand/ cor/ cxor 复合运算。

数值比较 - 有符号

CMP crfD, L, rA, rB

a <- EXTS(rA) 扩展符号到a (如果无符号比较 cmpl 则直接 a = rA)

b <- EXTS(rB)

扩展符号到b (如果无符号比较 cmpl 则直接 b = rB) If a < b then c = 0b100 设置小于标志

else if a > b then c = 0b010

设置大于标志 else c = 0b001 设置等于标志 CR[4 * crfD – 4 * crfD + 3] <- c || XER[SO] 记录4位状态

举例说明: cmpw rA, rB 比较 rA, rB 的低32位结果存cr0 (同 cmp 0, 0, rA, rB) cmpd rA, rB 比较 rA, rB 的全64位结果存cr0 (同 cmp 0, 1, rA, rB) cmpwc r3, rA, rB 比较 rA, rB 的低32位结果存cr3 (同 cmp 3, 0, rA, rB)

转移指令

指令B (branch )是绝对地址无条件跳转,BA 是相对地址无条件跳转,BL 是跳转前将下一条指令的地址记录到LR (可以用blr 跳转到LR 所指地址),BLA 是相对地址跳转,并将下条指令地址记录地址到LR 。

名 称 助记符 语法格式 解释

无条件转移

b (ba bl bla)

目标地址

子程序调用bl/bla

有条件转移 bc (bca bcl bcla) BO, BI, 目标地址 -

条件转移bclrx bclr (bclrl) BO, BI (地址取lr) 常用子程序返回 条件转移bcctrx bcctr (bcctrl) BO, BI (地址取ctr) -

跳转到LR 处

blr

同bclr 0b10100,0

条件跳转中 BI 用来表示具体需要测试的条件寄存器CR 的位,BO 用来表示测试方式,比如是测试大于/小于/等于还是测试计数器CTR 的值,故此blr 等同 bclr 0b10100, 0。

特性特性::指令的别名

PowerPC 指令助记符有大量别名:

比如 CMPW rA, rB 其实是 CMP 0, 0, rA, rB 比如 BEQ addr 其实是 BC 0xC, 2, addr 比如 BLR 其实是 BCLR 0x14, 0

转移指令如果没有指明条件寄存器,则默认使用CR0(CR 的0-3位);bca 相对于bc 或者ba 相对于b ,他们的指令码都相同,只是AA 位(是否用绝对地址)为1 ;bcl 相对于bc 或者bl 相对于b ,他们的指令码亦同,仅LK 位(是否记录地址)为1。

助记符 说 明

原 型

beq addr 如果等于则跳转addr bc 0b01100, 2, addr (CR0的EQ 位==1) beq cr2, addr 如果cr2为等于则跳转addr bc 0b01100, 10, addr (CR2的EQ 位==1) bne addr 如果不等于则跳转 bc 0b00100, 2, addr (CR0的EQ 位==1) blt addr 如果小于则跳转 bc 0b01100, 0, addr (CR0的LT 位==1) bgt addr 如果大于则跳转 bc 0b01100, 1, addr (CR0的GT 位==1) ble addr 如果小于等于则跳转 bc 0b00100, 1, addr (CR0的GT 位==0) bge addr 如果大于等于则跳转 bc 0b00100, 0, addr (CR0的LT 位==0) blr

跳转到LR 寄存器记录的地址

bclr 0b10100, 0, addr (无条件到LR )

问题3:如何跳转到R3所记录地址

BC, B 等都是用相对地址跳转的。如何实现类似C 里面的函数指针调用?

答案:需要用到LR 寄存器:

mtlr r3 将R3的值保存到LR blr 跳转到LR 所指位置

条件转移条件转移原理原理原理((了解了解))

BC BO, BI, target_addr (AA=0, LK=0)

m <- 32

If BO[2]=0 then CTR <- CTR - 1

如果BO[2]==0则计数器自减

ctr_ok <- BO[2] | BO[3] 判断计数器条件

cond_ok <- BO[0] | (CR[BI] == BO[1]) 判断条件寄存器某位是否符合需求 If ctr_ok & cond_ok then 如果两个条件同时成立则执行跳转 if AA then NIA <- iea EXTS(BD || 0b00) 如果使用绝对地址 else NIA <- iea CIA + EXTS(BD || 0b00) 如果使用相对地址

if LK then LR <- iea CIA + 4 判断是否记录指令地址到LR

注:NIA - 新指令地址;CIA - 当前指令地址;EXTS - 扩展正负符号;AA - 是否使用绝对跳转的标志;LK - 是否用LR 保存下条指令地址(CIA + 4)。

BO 字段常用操作码: BO=00100 如果条件成立(CR[BI]==0)则发生跳转 BO=01100 如果条件不成立(CR[BI]==1)则发生跳转 BO=10100 直接跳转

问题4:求绝对值指令原理

下面代码请直接用CMP/ BC 两条指令实现(提示:参考前面关于BC/CMP 两条指令原理)

cmpw r3, r4 beq _branch_1

答案(了解即可):

cmp 0, 0, r3, r4

bc 0b01100, 2, _branch_1

其实在实际开发中都是直接书写替代的别名

问题5:PowerPC 与x86的编码区别

PPC 指令系统比x86/arm 晦涩,同时RISC 载入常数等指令等要分两次;PPC 大部分指令都是三操作数,而x86几乎都是双操作数;PPC 指令比x86更细致精准,同样程序PPC 代码要比x86短。

示例示例::演示递归 – 求阶乘

接下来的程序将通过求阶乘演示递归。之前曾经说过:PPC 没有栈,故而实际递归时需要保存现场与返回地址的工作交给了应用程序,我们一般使用R1来模拟栈指针:

? _factoria:

/* 求阶乘,输入R3,返回R3 */ ?

mflr %r2

? stw %r2, -8(%r1) ? addi %r1, %r1, -60 ? _factoria.start:

?

cmpwi %cr0, %r3, 1

?bgt _factoria.n1 /* branch to n1 if r3 > 1 */

?li %r3, 1 /* return 1 (if r3 <= 1) */

?b _factoria.exit

?_factoria.n1:

?stw %r3, 8(%r1) /* save r3 to stack */

?addi %r3, %r3, -1 /* r3 = r3 - 1 */

?bl _factoria /* call _factoria */

?lwz %r11, 8(%r1) /* r11 = [r1 + 8] (old r3) */

?mullw %r3, %r3, %r11 /* r3 = r3 * r11 */

?_factoria.exit:

?addi %r1, %r1, 60 /* restore stack point */

?lwz %r2, -8(%r1) /* resotre LR */

?mtlr %r2

?blr

根据操作系统的不同,规定了不同的ABI(应用程序二进制接口),详细定义了栈如何操作,参数如何传递等关键接口规范,开发时需注意查看。

PowerPC 编译调试

交叉编译(在一个平台下编译另一个平台运行的程序)需要一台Unix机器或者Cygwin,下载并重新编译binutils即可:

# wget https://www.wendangku.net/doc/ab2063181.html,/gnu/binutils/binutils-2.18.tar.bz2

# tar -jvxf binutils-2.18.tar.bz2

# cd binutils-2.18

# ./configure --target=powerpc-linux-eabi

# make all install

模拟器QEMU最好在Linux环境中使用(才能支持用户模式模拟)

# apt-get install qemu (debian直接安装)

其他平台需要手工编译。所谓用户模式在于不需要模拟整个PPC操作系统,而是模拟执行PPC-Linux下二进制可执行文件,PPC程序的系统调用将会转化为本机Linux的系统调用。所以我们不需要再在QEMU下重新安装一个Mac OS X之类的系统:

# powerpc-linux-eabi-as -gstabs hello.s -o hello.o

# powerpc-linux-eabi-ld hello.o -o hello

# qemu-ppc ./hello

Hello, PowerPC World !!

#

上面是使用第一章中的hello.s进行编译,并在虚拟机中运行以后的效果。

PowerPC 指令优化

首先需要认识到PPC体系下的CPU种类繁多,对具体需要优化的环境需要详细了解。例如流水线的类型如何?以往习惯了x86的思维后,我们都以为主频越高越好,流水线越长越好。其实不然。越长的流水线,分支预测失误代价越大,单条指令通过的时间越长。因此如果单算执行一条指令的速度,流水线长20的P4 2.0GHz 速度还没有流水线长10的赛扬1.2GHz 快,而且Intel仅仅为了增加并行处理部分指令的机会而增加流水线长度,同时又要保持无法并行时的处理速度,为此只有增加主频,带来功耗的上升,以及分支预测失误的昂贵代价。

CPU需要根据科学型还是商务型及多媒体型来采取不同的设计优化策略:比如科学型计算机多用小而密集的循环计算,因此普通的分支预测命中率高(90%以上),因为大部分跳转都是向上跳转的循环,而商务型却只有50%的命中(大部分无规律的逻辑),多媒体型不但计算密集,而且内存吞吐量大。不同应用的CPU设计有所不同,优化也不同。

PowerPC以AS/400为例,多为短流水线体系,分支预测失误的代价更少,且主频更低(功耗更小),采用更“聪明”的预测机制,大部分主频很低,但速度惊人。以上流水线设计的两派技术体系争斗了十多年,各有千秋,很多主频比Intel低很多的PowerPC的芯片,却表现出了更优越的性能,而市场上大部分人只喜欢盲目追求主频,这是一个误区。

指令结对原则

1.指令结对

原则

在类PPC405/440的系统中,指令被分为下面三类的其中之一,类405/440系统能够在单一周期同时执行两条不属于同一种类的指令:

(1) 数据的加载与存储

(2) 任意义下处理:设置CR寄存器进行比较,分支,乘除SPR寄存器更新

(3) 其他种类操作:非SPR/CR寄存器更改,算术与逻辑

如果两条邻接的指令属于同一类别,那么第二条必须等待第一条处理完以后才能被调度,这样做就浪费了时钟周期;而如果邻接的两条指令属于上述不同类别且无结果依赖,那么两条指令能够被同时调度,这样做就能获得比较高的效率。

这与我们x86下优化的经验并部相同,在x86的流水线中只要无倚赖的代码基本都可以并行运行,比如我们可以并行处理若干无相关的加载或计算,从而在x86下达到较高的效率:

mov eax, [esi + 10] 三条无依赖加载能并行

mov ebx, [esi + 14]

mov ecx, [esi + 18]

add eax, edx 三条无依赖加法能并行

add ebx, edx

add ecx, edx

而这样在大多数类405/440的PPC下却是有问题的。整数计算属于同一类别,邻接的无依

赖计算指令不能如现代x86体系中得到同时运行;载入指令也相同,而整数计算和加载混合却能很好的并行调度:

lwz r3, 0(r10) 此加载和下一条加法无依赖,且属不同类别

add r4, r5, r5 加法能和前一条加载并行运行

lwz r6, 4(r10)

add r7, r8, r8

lwz r9, 8(r10)

add r3, r4, r4

因此如果我们的潜意识里过分熟悉x86优化方式,进而在用C开发的时候也会体现出来的话,可以说,这样的C代码在PPC下很难发挥效果的,即便编译器能优化,也需要给编译器留有优化的余地。

加载依赖原则

2.加载

依赖原则

当数据从缓存被加载到某寄存器的时候,需要数个周期以后数据才能被其他指令所使用,一条使用到刚被加载数据的指令需在数据被加载后第三个周期才能被调度。故在数据被加载与被使用两条指令之间的数个周期内形成了一段非常有效的优化区间,我们用来放置其他一些指令。加载与处理命令之间能放置的指令数决定于这些指令的种类,决定于他们是否能够结对并行处理,最大能有五条指令的优化空间。

指令周期说明

lwz r4,0(r5) n 加载指令被调度

addi r6,r6,0x20 n ADDI 能和加载指令在同周期调度

or r7,r8,r9 n + 1

stw r6,32(r1) n + 1

subf r10,r11,r12 n + 2

srawi r8,r8,4 n + 2

add r9,r4,r12 n + 3 R4 中的数据在加载命令的3周期后可以使用

在加载与使用命令之间能够并行插入的指令数取决于这些指令的混合方式,最少我们也可以插入两条指令进行优化。参考下面的指令,stw和lbz两条处于n+1和n+2周期的指令不能被结对并行执行,因为他们属于同一类别的指令。

指令周期说明

lwz r4,0(r5) n 加载指令被调度

stw r6,32(r1) n + 1 存储指令必须等待到n+1后才能被调度

lbz r11,20(r1) n + 2 加载指令必须等待到n+2后才能被调度

lwz r9,0(r4) n + 3 R4中的数据在加载明了的3周期后可以使用

虽然大部分加载指令只有一个目标寄存器,但是需要注意一些带“更新”功能的加载指令,诸如lwzu它除了更新目标寄存器外,同时也会更新源寄存器,此时对源寄存器的使用也必须等待该指令被完成执行以后才行。

3.指令依赖原则

同x86类似,有上下文依赖的指令不能同时被调度。在两条指令中,如果第一条指令更新的寄存器会被第二条指令用到,那么这两条指令不能被同时调度,利用这个特性我们将依赖关系的两条指令分开,并且插入至少一条指令完成优化。

比如我们在周期n用add r4,r5,r6更新了R4寄存器,那么就只能到周期n+1才能调度到使用R4寄存器的srawi r7,r4,4指令。在第一条指令的第n周期,没有指令能够与之并行执行而造成了浪费,所有正确的方式是在这两条指令之间加入一条无相关的指令,这样便能和add 指令进行结对而得到同时调度,充分利用了时钟周期。

4.缓存优化原则

缓存优化的方法基本和x86相同,这里再对缓存优化的原理做一下说明,即处理器要使用主存某地址的数据时,需要先将他们加载到缓存,然后才能处理,最后更新回主存去。根据前面的加载依赖原理的阐述,我们知道从缓存加载到寄存器需要三个时钟周期后才可以使用该寄存器,然而如果该地址的数据不在缓存中的话,前面就需要加上更多周期的等待周期,让数据先加载到缓存,最终再经过三个周期的等待后才能使用该数据。

为了降低直接从外存到缓存昂贵代价,现代的处理器都增加了一条预取指令,在x86下叫做prefetch而在PowerPC中叫做DCBT(Data Cache Block Touch):

DCBT rA, rB - 将(rA+rB)所表示的地址数据预取到缓存

该指令将提前告诉CPU将用到哪块内存,CPU提前将该内存读入缓存,几个周期以后等到用时就该指令已经在缓存中了。用dcbt同x86的prefetch指令,现代CPU的主要瓶颈在主存到缓存之间,高效使用缓存是优化的关键。

下面是一段x86下比memcpy快 1.6倍的内存拷贝代码,原因在于对缓存的使用上,先mm0-mm7顺序加载,再顺序写入,读入到mm0与从mm0写入中间间隔7条指令,让CPU 有足够的时间加载,同时使用了预取。

loop:

prefetchnta [esi + 256] 预取esi + 256地址的数据

movq mm0, [esi + 0] 加载esi + 0 到mm0

movq mm1, [esi + 8]

movq mm7, [esi + 56]

movntq [edi + 0], mm0 写入mm0到edi + 0

movntq [edi + 8], mm1 使用穿透缓存方式写入

movntq [edi + 56], mm7

add esi, 64 指针后移64字节

add edi, 64 指针后移64字节

dec ecx

jnz loop 判断计数器并循环跳转

而如果在PowerPC下写内存拷贝,我们就不能并列写若干加载指令,因为大部分PPC不能并行处理加载,我们需要将加载与存储交叉写:

loop:

dcbt r12, r11 预先加载(r12+r11) 处内存到缓存

lwzu r3, 4(r11) 加载内存到r3并且移动指针

lwzu r4, 4(r11)

lwzu r5, 4(r11) 争取加载指令与写入指令并行运行

stwu r3, 4(r10) 写入数据从r3并且移动指针

lwzu r6, 4(r11)

stwu r4, 4(r10)

lwzu r7, 4(r11)

stwu r3, 4(r10) 利用多寄存器的特点写下去

lwzu r8, 4(r11)

….

addi r9, 0, -1 减少计数器

cmpwi cr4, r9, 0

blt loop 计数器未到就跳转

该段程序有三处优化,首先是缓存预取,dcbt在每个循环预先取后面的内容,其次是充分利用PPC多寄存器的特点,最后是让加载和保存指令交叉进行充分的发挥并行作用。

如果你所使用的PowerPC没有DCBT指令的支持,那么我们可以用一些小技巧来达到缓存预取的效果,即将DCBT指令替换成一条lwz来加载该地址数据到一个无用的寄存器,这种方法称为“硬预取”,在x86中也能可以使用该方法来起到缓存预取的作用。

指令优化::

5.PPC的AltiVec ? 指令优化

在PowerPC G4后开始支持AltiVec ?,这是一套类似x86下MMX+SSE的SIMD指令集,提供128位的矢量并行计算(8bit/16bit/32bit三种计算元)的功能,使多媒体计算平均提高4-5倍,而具体的AltiVec ? 优化方法,超出本文叙述范围,读者可以自行查找相关资料。

最终优化方法::

6.最终优化方法

开启C编译器的汇编输出,在最大优化模式下思考编译器的优化策略。反复阅读对应CPU 的官方文档,试验、试验、再试验!最终您能写出漂亮高效的PPC代码。

参考资料

《PowerPC860嵌入式系统及应用》,机械工业出版社,陈晓竹,2006

《Linux PowerPC详解-核心篇》, 机械工业出版社, 王齐, 1997

《罗彻斯特城堡》,机械工业出版社,IBM,2003

《基于POWERPC的嵌入式LINUX》, 北京航空航天大学出版社, 漆昭铃, 2004

PowerPC Architecture Book,

https://www.wendangku.net/doc/ab2063181.html,/developerworks/eserver/library/es-archguide-v2.html

Software optimization techniques for PowerPC 405 and 440,

https://www.wendangku.net/doc/ab2063181.html,/developerworks/eserver/library/es-plib1app.html

Unrolling AltiVec Part 1 - Introducing PowerPC SIMD Unit

https://www.wendangku.net/doc/ab2063181.html,/developerworks/library/pa-unrollav1/

汇编语言 快速入门

“哎哟,哥们儿,还捣鼓汇编呢?那东西没用,兄弟用VB"钓"一个API就够你忙活个十天半月的,还不一定搞出来。”此君之言倒也不虚,那吾等还有无必要研他一究呢?(废话,当然有啦!要不然你写这篇文章干嘛。)别急,别急,让我把这个中原委慢慢道来:一、所有电脑语言写出的程序运行时在内存中都以机器码方式存储,机器码可以被比较准确的翻译成汇编语言,这是因为汇编语言兼容性最好,故几乎所有跟踪、调试工具(包括WIN95/98下)都是以汇编示人的,如果阁下对CRACK颇感兴趣……;二、汇编直接与硬件打交道,如果你想搞通程序在执行时在电脑中的来龙去脉,也就是搞清电脑每个组成部分究竟在干什么、究竟怎么干?一个真正的硬件发烧友,不懂这些可不行。三、如今玩DOS的多是“高手”,如能像吾一样混入(我不是高手)“高手”内部,不仅可以从“高手”朋友那儿套些黑客级“机密”,还可以自诩“高手”尽情享受强烈的虚荣感--#$%&“醒醒!” 对初学者而言,汇编的许多命令太复杂,往往学习很长时间也写不出一个漂漂亮亮的程序,以致妨碍了我们学习汇编的兴趣,不少人就此放弃。所以我个人看法学汇编,不一定要写程序,写程序确实不是汇编的强项,大家不妨玩玩DEBUG,有时CRACK出一个小软件比完成一个程序更有成就感(就像学电脑先玩游戏一样)。某些高深的指令事实上只对有经验的汇编程序员有用,对我们而言,太过高深了。为了使学习汇编语言有个好的开始,你必须要先排除那些华丽复杂的命令,将注意力集中在最重要的几个指令上(CMP LOOP MOV JNZ……)。但是想在啰里吧嗦的教科书中完成上述目标,谈何容易,所以本人整理了这篇超浓缩(用WINZIP、WINRAR…依次压迫,嘿嘿!)教程。大言不惭的说,看通本文,你完全可以“不经意”间在前辈或是后生卖弄一下DEBUG,很有成就感的,试试看!那么――这个接下来呢?――Here we go!(阅读时看不懂不要紧,下文必有分解) 因为汇编是通过CPU和内存跟硬件对话的,所以我们不得不先了解一下CPU和内存:(关于数的进制问题在此不提) CPU是可以执行电脑所有算术╱逻辑运算与基本I/O控制功能的一块芯片。一种汇编语言只能用于特定的CPU。也就是说,不同的CPU其汇编语言的指令语法亦不相同。个人电脑由1981年推出至今,其CPU发展过程为:8086→80286→80386→80486→PENTIUM →……,还有AMD、CYRIX等旁支。后面兼容前面CPU的功能,只不过多了些指令(如多能奔腾的MMX指令集)、增大了寄存器(如386的32位EAX)、增多了寄存器(如486的FS)。为确保汇编程序可以适用于各种机型,所以推荐使用8086汇编语言,其兼容性最佳。本文所提均为8086汇编语言。寄存器(Register)是CPU内部的元件,所以在寄存器之间的数据传送非常快。用途:1.可将寄存器内的数据执行算术及逻辑运算。2.存于寄存器内的地址可用来指向内存的某个位置,即寻址。3.可以用来读写数据到电脑的周边设备。8086有8个8位数据寄存器,这些8位寄存器可分别组成16位寄存器:AH&AL=AX:累加寄存器,常用于运算;BH&BL=BX:基址寄存器,常用于地址索引;CH&CL=CX:计数寄存器,常用于计数;DH&DL=DX:数据寄存器,常用于数据传递。为了运用所有的内存空间,8086设定了四个段寄存器,专门用来保存段地址:CS(Code Segment):代码段寄存器;DS(Data Segment):数据段寄存器;SS(Stack Segment):堆栈段寄存器;ES(Extra Segment):附加段寄存器。当一个程序要执行时,就要决定程序代码、数据和堆栈各要用到内存的哪些位置,通过设定段寄存器CS,DS,SS来指向这些起始位置。通常是将DS固定,而根据需要修改CS。所以,程序可以在可寻址空间小于64K的情况下被写成任意大小。所以,程序和其数据组合起来的大小,限制在DS所指的64K内,这就是COM文件不得大于64K的原因。8086以内存做为战场,用寄存器做为军事基地,以加速工作。除了前面所提的寄存器外,还有一些特殊功能的寄存器:IP(Intruction Pointer):指

软件破解入门教程

先教大家一些基础知识,学习破解其实是要和程序打交道的,汇编是破解程序的必备知识,但有可能部分朋友都没有学习过汇编语言,所以我就在这里叫大家一些简单实用的破解语句吧! ---------------------------------------------------------------------------------------------------------------- 语句:cmp a,b //cmp是比较的意思!在这里假如a=1,b=2 那么就是a与b比较大小. mov a,b //mov是赋值语句,把b的值赋给a. je/jz //就是相等就到指定位置(也叫跳转). jne/jnz //不相等就到指定位置. jmp //无条件跳转. jl/jb //若小于就跳. ja/jg //若大于就跳. jge //若大于等于就跳. 这里以一款LRC傻瓜编辑器为例,讲解一下软件的初步破解过程。大家只要认真看我的操作一定会!假如还是不明白的话提出难点帮你解决,还不行的话直接找我!有时间给你补节课!呵呵! 目标:LRC傻瓜编辑器杀杀杀~~~~~~~~~ 简介:本软件可以让你听完一首MP3歌曲,便可编辑完成一首LRC歌词。并且本软件自身还带有MP3音乐播放和LRC歌词播放功能,没注册的软件只能使用15天。 工具/原料 我们破解或给软件脱壳最常用的软件就是OD全名叫Ollydbg,界面如图: 它是一个功能很强大的工具,左上角是cpu窗口,分别是地址,机器码,汇编代码,注释;注释添加方便,而且还能即时显示函数的调用结果,返回值. 右上角是寄存器窗口,但不仅仅反映寄存器的状况,还有好多东东;双击即可改变Eflag的值,对于寄存器,指令执行后发生改变的寄存器会用红色突出显示. cpu窗口下面还有一个小窗口,显示当前操作改变的寄存器状态. 左下角是内存窗口.可以ascii或者unicode两种方式显示内存信息. 右下角的是当前堆栈情况,还有注释啊. 步骤/方法 1. 我们要想破解一个软件就是修改它的代码,我们要想在这代码的海洋里找到我们破解关键的代码确实很棘 手,所以我们必须找到一定的线索,一便我们顺藤摸瓜的找到我们想要的东东,现在的关键问题就是什么

汇编语言知识大全

第一章基础知识: 一.机器码:1.计算机只认识0,1两种状态。而机器码只能由0,1组成。故机器码相当难认,故产生了汇编语言。 2.其中汇编由三类指令形成:汇编指令(有机器码对应),伪指令,其他符号(编译的时候有用)。 每一总CPU都有自己的指令集;注意学习的侧重点。 二.存储器:1.存储单元中数据和指令没任何差别。 2.存储单元:Eg:128个储存单元(0~127)128byte。 线: 1.地址总线:寻址用,参数(宽度)为N根,则可以寻到2^N个内存单元。 据总线:传送数据用,参数为N根,一次可以传送N/8个存储单元。 3.控制总线:cpu对元器件的控制能力。越多控制力越强。 四.内存地址空间:1.由地址总线决定大小。 2.主板:cpu和核心器件(或接口卡)用地址总线,数据总线,控制总 线连接起来。 3.接口卡:由于cpu不能直接控制外设,需通过接口卡间接控制。

4.各类存储器芯片:RAM,BIOS(主板,各芯片)的ROM,接卡槽的 RAM CPU在操控他们的时候,把他们都当作内存来对待,把他们总的看作一个由 若干个存储单元组成的逻辑存储器,即我们所说的内存地址空间。 自己的一点理解:CPU对内存的操作是一样的,但是在cpu,内存,芯片之间的硬件本身所牵扯的线是不同的。所以一些地址的功能是对应一些芯片的。 第二章寄存器 引入:CPU中含有运算器,寄存器,控制器(由内部总线连接)。而寄存器是可以用来指令读写的部件。8086有14个寄存器(都是16位,2个存储空间)。 一.通用寄存器(ax,bx,cx,dx),16位,可以分为高低位 注意1.范围:16位的2^16-1,8位的2^8-1 2.进行数据传送或运算时要注意位数对应,否则会报错 二.字:1. 1个字==2个字节。 2. 在寄存器中的存储:0x高位字节低位字节;单元认定的是低单元 数制,16进制h,2进制b

IAR -arm 入门教程

IAR 使用说明 关于文档(初版): 1.主要是为了给IAR的绝对新手作参考用 2.emot制件,由Zigbee & IAR 学习小组保持修订权 3.希望用IAR朋友能将它修订完善 4.任何人可无偿转载、传播本文档,无须申请许可,但请保留文档来源及标志 5.如无重大升级,请沿用主版本号 版本 版本号制作时间制定人/修改人说明 1.00 2008/7/27 emot 初版(仅供新手参考) 1.01 2010/8/19 Emot 增加 下载程序(第四章) 在线调试程序(第五章) 序: 其实IAR和keil区别也没有多大,不过很多人就是怕(当初我也怕)。怕什么呢,怕学会了,真的就是害怕学习的心理让新手觉得IAR是个不好用的或者说“还不会用的”一个工具吧。我也是一个刚毕业的小子,如果说得不妥,还请大家来点砖头,好让小组筑高起来。(Zigbee & IAR 学习小组地址是https://www.wendangku.net/doc/ab2063181.html,/673) 初版我将会说明以下3个问题,IAR的安装、第一个IAR工程的建立和工作编译。这是我写的第一个使用说明,不足的以后补充吧。 一、IAR软件安装图解 1.打开IAR软件安装包进入安装界面 打开软件开发包

软件安装界面 2.按照提示步骤执行,一直到授权页面,输入序列号,IAR中有两层序列号,所以要输入两 组序列号。 输入第一组序列号

3.选择安装路径(最好默认,不默认也不影响使用) 路径选择页面

修改路径4.选择全部安装(Full) 选择全部安装5.按提示知道安装完成。

安装完成页面 二、新建第一个IAR工程 用IAR首先要新建的是工作区,而不是工程。在工作区里再建立工程,一个工作区里似乎也不能建多个工程(我试过,但没成功,不知道IAR里提出workspace的概念是为什么?)要不打IAR的help来看,说清楚也是头痛的事,先知道有要在工作空间里建工程就对了。新建IAR工作空间,首先是菜单File里选择Open再选择Workspace,为方便说明再遇到菜 单我就直接说成File-Open-Workspace这样了。看了下面图上的红圈就知道是怎么回事了。 接着就会看到一片空白。这时就是新的“办公区”了。

Linux基本反汇编结构与GDB入门

Linux下的汇编与Windows汇编最大的不同就是第一个操作数是原操作数,第二个是目的操作数,而Windows下却是相反。 1、基本操作指令 简单的操作数类型说明,一般有三种, (1)立即数操作数,也就是常数值。立即数的书写方式是“$”后面跟一个整数,比如$0x1F,这个会在后面的具体分析中见到很多。 (2)寄存器操作数,它表示某个寄存器的内容,用符号Ea来表示任意寄存器a,用引用R[Ea]来表示它的值,这是将寄存器集合看成一个数组R,用寄存器表示符作为索引。 (3)操作数是存储器引用,它会根据计算出来的地址(通常称为有效地址)访问某个存储器位置。用符号Mb[Addr]表示对存储在存储器中从地址Addr开始的b字节值的引用。通常可以省略下标b。 图1表示有多种不同的寻址模式,一个立即数偏移Imm,一个基址寄存器Eb,一个变址或索引寄存器Ei和一个伸缩因子s。有效地址被计算为Imm+R[Eb]+R[Ei]*s,对于这中寻址方式,我们可以在数组或者结构体中进行对元

注:操作数可以是立即数值、寄存器值或是来自存储器的值,伸缩因子必须是1、2、4、或者是8。从上面的图我们就可以大致了解操作数的类型了。 在操作指令中,最频繁使用的指令是执行数据传送的指令。对于传送指令的两个操作数不能都指向存储器位置(我的理解是一般存储器存储的都是地址,不能够对地址和地址进行操作)。将一个值从一个存储器位置拷到另一个存储器位置需要两条指令——第一条指令将源值加载到寄存器中,第二条将该寄存器值写入到目的位置。下面给出源操作数和目的操作数的五种可能组合。 1、movl $0x4050, %eax 立即数——寄存器 2、movl %ebp, %esp 寄存器——寄存器 3、movl (%edi, %ecx), %eax 存储器——寄存器 4、movl $-17, (%esp) 立即数——存储器 5、movl %eax, -12(%ebp) 寄存器——存储器 注意这里的指令mov可能有不同的形式,不同平台的汇编一般是有些不一样的, 结合例子来进行讲解一下指令的具体操作,在这里将会正式接触到Linux下的GCC开发环境和GDB调试器,不过都是比较简单的应用。我的Linux操作系统是Ubuntu9.10,其它版本的差别应该不大, 如果我们要编写一个程序,我们可以用Linux下自带的vi或vim编辑器,studyrush@studyrush-desktop:~/C$ vi exchange.c vi 后面加我们要创建的程序文件的名字,在这里是exchange.c studyrush@studyrush-desktop:~/C$ gcc -o exchange exchange.c gcc -o exchange exchange.c 或gcc exchange –o exchange这两者都可以对源文件进行编译,-o exchange 表示对我们要输出的文件名称,可能表达的不够准确,大家可以先熟悉一下gcc编译器,应该就会明白的了。 studyrush@studyrush-desktop:~/C$ ./exchange 点加斜线再加输出文件名就表示运行程序,下面是运行的结果。 a = 3, b = 4

6、汇编学习从入门到精通(荐书)

汇编学习从入门到精通Step By Step 2007年12月15日星期六00:34 信息来源:https://www.wendangku.net/doc/ab2063181.html,/hkbyest/archive/2007/07/22/1702065.aspx Cracker,一个充满诱惑的词。别误会,我这里说的是软件破解,想做骇客的一边去,这年头没人说骇客,都是“黑客”了,嘎嘎~ 公元1999年的炎热夏季,我捧起我哥留在家的清华黄皮本《IBM-PC汇编语言程序设计》,苦读。一个星期后我那脆弱的小心灵如玻璃般碎裂了,为了弥补伤痛我哭爹求妈弄了8k大洋配了台当时算是主流的PC,要知道那是64M内存!8.4G硬盘啊!还有传说中的Celeon 300A CPU。不过很可惜的是在当时那32k小猫当道的时代,没有宽带网络,没有软件,没有资料,没有论坛,理所当然我对伟大的计算机科学体系的第一步探索就此夭折,此时陪伴我的是那些盗版光盘中的游戏,把CRACK_XXX文件从光盘复制到硬盘成了时常的工作,偶尔看到光盘中的nfo 文件,心里也闪过一丝对破解的憧憬。 上了大学后有网可用了,慢慢地接触到了一些黑客入侵的知识,想当黑客是每一个充满好奇的小青年的神圣愿望,整天看这看那,偷偷改了下别人的网页就欢喜得好像第一次偷到鸡的黄鼠狼。 大一开设的汇编教材就是那不知版了多少次的《IBM-PC汇编语言程序设计》,凭着之前的那星期苦读,考试混了个80分。可惜当时头脑发热,大学60分万岁思想无疑更为主流,现在想想真是可惜了宝贵的学习时间。 不知不觉快毕业了,这时手头上的《黑客防线》,《黑客X档案》积了一大摞,整天注来注去的也厌烦了,校园网上的肉鸡一打一打更不知道拿来干什么。这时兴趣自然转向了crack,看着杂志上天书般的汇编代码,望望手头还算崭新的汇编课本,叹了口气,重新学那已经忘光了的汇编语言吧。咬牙再咬牙,看完寻址方式那章后我还是认输,不认不行啊,头快裂了,第三次努力终告失败。虽然此时也可以爆破一些简单的软件,虽然也知道搞破解不需要很多的汇编知识,但我还是固执地希望能学好这门基础中的基础课程。 毕业了,进入社会了,找工作,上班,换工作成了主流旋律,每天精疲力尽的哪有时间呢?在最初的中国移动到考公务员再到深圳再到家里希望的金融机构,一系列的曲折失败等待耗光了我的热情,我失业了,赋闲在家无所事事,唯一陪伴我的是那些杂志,课本,以及过时的第二台电脑。我不想工作,我对找工作有一种恐惧,我靠酒精麻醉自己,颓废一段日子后也觉得生活太过无聊了,努力看书考了个CCNA想出去,结果还是被现实的就业环境所打败。三年时间,一无所获。 再之后来到女朋友处陪伴她度过刚毕业踏入社会工作的适应时期,这段时间随便找了个电脑技术工作,每月赚那么个几百块做生活费。不过这半年让我收获比较大的就是时间充裕,接触到了不少新东西,我下定决心要把汇编学好,这时我在网上看到了别人推荐的王爽《汇编语言》,没抱什么希望在当当网购了人生中的第一次物,19块6毛,我记得很清楚,呵呵。 废话终于完了,感谢各位能看到这里,下面进入正题吧。

Windows X86-64位汇编语言入门

Windows X86-64位汇编语言入门 Windows X64汇编入门(1) 最近断断续续接触了些64位汇编的知识,这里小结一下,一是阶段学习的回顾,二是希望对64位汇编新手有所帮助。我也是刚接触这方面知识,文中肯定有错误之处,大家多指正。 文章的标题包含了本文的四方面主要内容: (1)Windows:本文是在windows环境下的汇编程序设计,调试环境为Windows Vista 64位版,调用的均为windows API。 (2)X64:本文讨论的是x64汇编,这里的x64表示AMD64和Intel的EM64T,而不包括IA64。至于三者间的区别,可自行搜索。 (3)汇编:顾名思义,本文讨论的编程语言是汇编,其它高级语言的64位编程均不属于讨论范畴。 (4)入门:既是入门,便不会很全。其一,文中有很多知识仅仅点到为止,更深入的学习留待日后努力。其二,便于类似我这样刚接触x64汇编的新手入门。 本文所有代码的调试环境:Windows Vista x64,Intel Core 2 Duo。 1. 建立开发环境 1.1 编译器的选择 对应于不同的x64汇编工具,开发环境也有所不同。最普遍的要算微软的MASM,在x64环境中,相应的编译器已经更名为ml64.exe,随Visual Studio 2005一起发布。因此,如果你是微软的忠实fans,直接安装VS2005既可。运行时,只需打开相应的64位命令行窗口(图1),便可以用ml64进行编译了。

第二个推荐的编译器是GoASM,共包含三个文件:GoASM编译器、GoLINK链接器和GoRC 资源编译器,且自带了Include目录。它的最大好外是小,不用为了学习64位汇编安装几个G 的VS。因此,本文的代码就在GoASM下编译。 第三个Yasm,因为不熟,所以不再赘述,感兴趣的朋友自行测试吧。 不同的编译器,语法会有一定差别,这在下面再说。 1.2 IDE的选择 搜遍了Internet也没有找到支持asm64的IDE,甚至连个Editor都没有。因此,最简单的方法是自行修改EditPlus的masm语法文件,这也是我采用的方法,至少可以得到语法高亮。当然,如果你懒得动手,那就用notepad吧。 没有IDE,每次编译时都要手动输入不少参数和选项,做个批处理就行了。 1.3 硬件与操作系统 硬件要求就是64位的CPU。操作系统也必须是64位的,如果在64位的CPU上安装了

汇编语言入门教程

汇编语言入门教程 2007-04-29 22:04对初学者而言,汇编的许多命令太复杂,往往学习很长时间也写不出一个漂漂亮亮的程序,以致妨碍了我们学习汇编的兴趣,不少人就此放弃。所以我个人看法学汇编,不一定要写程序,写程序确实不是汇编的强项,大家不妨玩玩DEBUG,有时CRACK 出一个小软件比完成一个程序更有成就感(就像学电脑先玩游戏一样)。某些高深的指令事实上只对有经验的汇编程序员有用,对我们而言,太过高深了。为了使学习汇编语言有个好的开始,你必须要先排除那些华丽复杂的命令,将注意力集中在最重要的几个指令上(CMP LOOP MOV JNZ……)。但是想在啰里吧嗦的教科书中完成上述目标,谈何容易,所以本人整理了这篇超浓缩(用WINZIP、WINRAR…依次压迫,嘿嘿!)教程。大言不惭的说,看通本文,你完全可以“不经意”间在前辈或是后生卖弄一下DEBUG,很有成就感的,试试看!那么――这个接下来呢?――Here we go!(阅读时看不懂不要紧,下文必有分解) 因为汇编是通过CPU和内存跟硬件对话的,所以我们不得不先了解一下CPU和内存:(关于数的进制问题在此不提) CPU是可以执行电脑所有算术╱逻辑运算与基本I/O 控制功能的一块芯片。一种汇编语言只能用于特定的CPU。也就是说,不同的CPU其汇编语言的指令语法亦不相同。个人电脑由1981年推出至今,其CPU发展过程为:8086→80286→80386→80486→PENTIUM →……,还有AMD、CYRIX等旁支。后面兼容前面CPU的功能,只不过多了些指令(如多能奔腾的MMX指令集)、增大了寄存器(如386的32位EAX)、增多了寄存器(如486的FS)。为确保汇编程序可以适用于各种机型,所以推荐使用8086汇编语言,其兼容性最佳。本文所提均为8086汇编语言。寄存器(Register)是CPU内部的元件,所以在寄存器之间的数据传送非常快。用途:1.可将寄存器内的数据执行算术及逻辑运算。2.存于寄存器内的地址可用来指向内存的某个位置,即寻址。3.可以用来读写数据到电脑的周边设备。8086 有8个8位数据寄存器,这些8位寄存器可分别组成16位寄存器:AH&AL=AX:累加寄存器,常用于运算;BH&BL=BX:基址寄存器,常用于地址索引;CH&CL=CX:计数寄存器,常用于计数;DH&DL=DX:数据寄存器,常用于数据传递。为了运用所有的内存空间,8086设定了四个段寄存器,专门用来保存段地址:CS(Code Segment):代码段寄存器;DS(Data Segment):数据段寄存器;SS(Stack Segment):堆栈段寄存器;ES(Extra Segment):附加段寄存器。当一个程序要执行时,就要决定程序代码、数据和堆栈各要用到内存的哪些位置,通过设定段寄存器CS,DS,SS 来指向这些起始位置。通常是将DS固定,而根据需要修改CS。所以,程序可以在可寻址空间小于64K的情况下被写成任意大小。所以,程序和其数据组合起来的大小,限制在DS 所指的64K内,这就是COM文件不得大于64K的原因。8086以内存做为战场,用寄存器做为军事基地,以加速工作。除了前面所提的寄存器外,还有一些特殊功能的寄存器:IP(Intruction Pointer):指令指针寄存器,与CS配合使用,可跟踪程序的执行过程;SP(Stack Pointer):堆栈指针,与SS配合使用,可指向目前的堆栈位置。BP(Base Pointer):基址指针寄存器,可用作SS的一个相对基址位置;SI(Source Index):源变址寄存器可用来存放相对于DS 段之源变址指针;DI(Destination Index):目的变址寄存器,可用来存放相对于ES 段之目的变址指针。还有一个标志寄存器FR(Flag Register),有九个有意义的标志,将在下文用到时详细说明。

汇编语言入门

汇编语言入门教程 对初学者而言,汇编的许多命令太复杂,往往学习很长时间也写不出一个漂漂亮亮的程序,以致妨碍了我们学习汇编的兴趣,不少人就此放弃。所以我个人看法学汇编,不一定要写程序,写程序确实不是汇编的强项,大家不妨玩玩DEBUG,有时CRACK出一个小软件比完成一个程序更有成就感(就像学电脑先玩游戏一样)。某些高深的指令事实上只对有经验的汇编程序员有用,对我们而言,太过高深了。为了使学习汇编语言有个好的开始,你必须要先排除那些华丽复杂的命令,将注意力集中在最重要的几个指令上(CMP LOOP MOV JNZ……)。但是想在啰里吧嗦的教科书中完成上述目标,谈何容易,所以本人整理了这篇超浓缩(用WINZIP、WINRAR…依次压迫,嘿嘿!)教程。大言不惭的说,看通本文,你完全可以“不经意”间在前辈或是后生卖弄一下DEBUG,很有成就感的,试试看!那么――这个接下来呢?――Here we go!(阅读时看不懂不要紧,下文必有分解) 因为汇编是通过CPU和内存跟硬件对话的,所以我们不得不先了解一下CPU和内存:(关于数的进制问题在此不提) CPU是可以执行电脑所有算术╱逻辑运算与基本I/O 控制功能的一块芯片。一种汇编语言只能用于特定的CPU。也就是说,不同的CPU其汇编语言的指令语法亦不相同。个人电脑由1981年推出至今,其CPU发展过程为:8086→80286→80386→80486→PENTIUM →……,还有AMD、CYRIX等旁支。后面兼容前面CPU的功能,只不过多了些指令(如多能奔腾的MMX指令集)、增大了寄存器(如386的32位EAX)、增多了寄存器(如486的FS)。为确保汇编程序可以适用于各种机型,所以推荐使用8086汇编语言,其兼容性最佳。本文所提均为8086汇编语言。寄存器(Register)是CPU内部的元件,所以在寄存器之间的数据传送非常快。用途:1.可将寄存器内的数据执行算术及逻辑运算。2.存于寄存器内的地址可用来指向内存的某个位置,即寻址。3.可以用来读写数据到电脑的周边设备。8086 有8个8位数据寄存器,这些8位寄存器可分别组成16位寄存器:AH&AL=AX:累加寄存器,常用于运算;BH&BL=BX:基址寄存器,常用于地址索引;CH&CL=CX:计数寄存器,常用于计数;DH&DL=DX:数据寄存器,常用于数据传递。为了运用所有的内存空间,8086设定了四个段寄存器,专门用来保存段地址:CS(Code Segment):代码段寄存器;DS(Data Segment):数据段寄存器;SS(Stack Segment):堆栈段寄存器;ES(Extra Segment):附加段寄存器。当一个程序要执行时,就要决定程序代码、数据和堆栈各要用到内存的哪些位置,通过设定段寄存器CS,DS,SS 来指向这些起始位置。通常是将DS固定,而根据需要修改CS。所以,程序可以在可寻址空间小于64K的情况下被写成任意大小。所以,程序和其数据组合起来的大小,限制在DS 所指的64K内,这就是COM文件不得大于64K的原因。8086以内存做为战场,用寄存器做为军事基地,以加速工作。除了前面所提的寄存器外,还有一些特殊功能的寄存器:IP(Intruction Pointer):指令指针寄存器,与CS配合使用,可跟踪程序的执行过程;SP(Stack Pointer):堆栈指针,与SS配合使用,可指向目前的堆栈位置。BP(Base Pointer):基址指针寄存器,可用作SS 的一个相对基址位置;SI(Source Index):源变址寄存器可用来存放相对于DS段之源变址指针;DI(Destination Index):目的变址寄存器,可用来存放相对于ES 段之目的变址指针。还有一个标志寄存器FR(Flag Register),有九个有意义的标志,将在下文用到时详细说明。 内存是电脑运作中的关键部分,也是电脑在工作中储存信息的地方。内存组织有许多可存放

OllyDBG完美教程

关键词:OD、OllyDBG、破解入门、调试专用工具、反汇编 一、OllyDBG 的安装与配置 OllyDBG 1.10 版的发布版本是个 ZIP 压缩包,只要解压到一个目录下,运行 OllyDBG.exe 就可以了。汉化版的发布版本是个 RAR 压缩包,同样只需解压到一个目录下运行 OllyDBG.exe 即可: OllyDBG 中各个窗口的功能如上图。简单解释一下各个窗口的功能,更详细的内容可以参考 TT 小组翻译的中文帮助: 反汇编窗口:显示被调试程序的反汇编代码,标题栏上的地址、HEX 数据、反汇编、注释可以通过在窗口中右击出现的菜单界面选项->隐藏标题或显示标题来进行切换是否显示。用鼠标左键点击注释标签可以切换注释显示的方式。

寄存器窗口:显示当前所选线程的 CPU 寄存器内容。同样点击标签寄存器 (FPU) 可以切换显示寄存器的方式。 信息窗口:显示反汇编窗口中选中的第一个命令的参数及一些跳转目标地址、字串等。 数据窗口:显示内存或文件的内容。右键菜单可用于切换显示方式。 堆栈窗口:显示当前线程的堆栈。 要调整上面各个窗口的大小的话,只需左键按住边框拖动,等调整好了,重新启动一下 OllyDBG 就可以生效了。 启动后我们要把插件及 UDD 的目录配置为绝对路径,点击菜单上的选项->界面,将会出来一个界面选项的对话框,我们点击其中的目录标签: 因为我这里是把 OllyDBG 解压在 F:\OllyDBG 目录下,所以相应的 UDD 目录及插件目录按图上配置。还有一个常用到的标签就是上图后面那个字体,在这里你可以更改 OllyDBG 中显示的字体。上图中其它的选项可以保留为默认,若有需要也可以自己修改。修改完以后点击确定,弹出一个对话框,说我们更改了插件路径,要重新启动 OllyDBG。在这个对话框上点确定,重新启动一下 OllyDBG,我们再到界面选项中看一下,会发现我们原先设置好的路径都已保存了。有人可能知道插件的作用,但对那个 UDD 目录

汇编语言基础知识

汇编语言基础知识 汇编语言是直接在硬件之上工作的编程语言,首先要了解硬件系统的结构,才能有 效地应用汇编语言对其编程,因此,本章对硬件系统结构的问题进行部分探讨,首先介绍了计算机的基本结构、Intel 公司微处理器的发展、计算机的语言以及汇编语言的特点,在此基础上重点介绍寄存器、内存组织等汇编语言所涉及到的基本知识。 1.1 微型计算机概述 微型计算机由中央处理器(Central Processing Unit ,CPU )、存储器、输入输出接口电路和总线构成。CPU 如同微型计算机的心脏,它的性能决定了整个微型计算机的各项关键指标。存储器包括随机存储器(Random Access Memory ,RAM )和只读存储器(Read Only Memory ,ROM )。输入输出接口电路用来连接外部设备和微型计算机。总线为CPU 和其他部件之间提供数据、地址和控制信息的传输通道。如图1.1所示为微型计算机的基本结构。 外部设备存储器输入输出接口电路中央处理器 CPU 地址总线 数据总线 控制总线 图1.1 微型计算机基本结构 特别要提到的是微型计算机的总线结构,它使系统中各功能部件之间的相互关系变 为各个部件面向总线的单一关系。一个部件只要符合总线结构标准, 就可以连接到采用这种总线结构的系统中,使系统功能得到扩展。 数据总线用来在CPU 与内存或其他部件之间进行数据传送。它是双向的,数据总线 的位宽决定了CPU 和外界的数据传送速度,8位数据总线一次可传送一个8位二进制数据(即一个字节),16位数据总线一次可传送两个字节。在微型计算机中,数据的含义是广义的,数据总线上传送的不一定是真正的数据,而可能是指令代码、状态量或控制量。 地址总线专门用来传送地址信息,它是单向的,地址总线的位数决定了 CPU 可以直接寻址的内存范围。如 CPU 的地址总线的宽度为N ,则CPU 最多可以寻找2N 个内存单 元。

汇编语言-王爽-完美高清版视频教程

汇编语言》-王爽-完美高清版-零基础汇编语言入门书籍PDF格式 同时按ctrl+要下载的地址既可下载对应的视频 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f61cb107c8 001第一章- 基础知识01 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6806f45b8 002第一章- 基础知识02 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6ec42d4d3 003第一章- 基础知识03 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6deb05ec4 004第一章-基础知识04 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6e51f6838 005第一章- 基础知识05 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f66edaf8d3 006第二章- 寄存器(CPU工作原理)01 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6d07e07b9 007第二章- 寄存器(CPU工作原理)02 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6d7f585a8 008第二章- 寄存器(CPU工作原理)03 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f639d8b3cf 009第二章- 寄存器(CPU工作原理)04 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6dcadbde6 010第二章- 寄存器(CPU工作原理)05 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6ea3f01c1 011第二章- 寄存器(CPU工作原理)06 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f65b96a06f 012第二章- 寄存器(CPU工作原理)07 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f682da085a 013第三章- 寄存器(内存访问)01 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6486e698 014第三章- 寄存器(内存访问)02 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6b7491d9f 015第三章- 寄存器(内存访问)03 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f622b7f9a7 016第三章- 寄存器(内存访问)04 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f64e2424b9 017第三章- 寄存器(内存访问)05 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6e5132d4d 018第三章- 寄存器(内存访问)06 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f655c10e86 019第三章- 寄存器(内存访问)07 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6b22e64e6 020第四章- 第一个程序01 下载地址:https://www.wendangku.net/doc/ab2063181.html,/file/f6812126a4

OllyICE反汇编教程及汇编命令详解

OllyICE反汇编教程及汇编命令详解[转] 2009-02-11 08:09 OllyICE反汇编教程及汇编命令详解 内容目录 计算机寄存器分类简介 计算机寄存器常用指令 一、常用指令 二、算术运算指令 三、逻辑运算指令 四、串指令 五、程序跳转指令 ------------------------------------------ 计算机寄存器分类简介: 32位CPU所含有的寄存器有: 4个数据寄存器(EAX、EBX、ECX和EDX) 2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP) 6个段寄存器(ES、CS、SS、DS、FS和GS) 1个指令指针寄存器(EIP) 1个标志寄存器(EFlags) 1、数据寄存器 数据寄存器主要用来保存操作数和运算结果等信息,从而节省读取操作数所需占用总线和访问存储器的时间。 32位CPU有4个32位的通用寄存器EAX、EBX、ECX和EDX。 对低16位数据的存取,不会影响高16位的数据。 这些低16位寄存器分别命名为:AX、BX、CX和DX,它和先前的CPU中的寄存器相一致。4个16位寄存器又可分割成8个独立的8位寄存器(AX:AH-AL、BX:BH-BL、CX:CH-CL、DX:DH-DL),每个寄存器都有自己的名称,可独立存取。 程序员可利用数据寄存器的这种“可分可合”的特性,灵活地处理字/字节的信息。 寄存器EAX通常称为累加器(Accumulator),用累加器进行的操作可能需要更少时间。可用于乘、除、输入/输出等操作,使用频率很高; 寄存器EBX称为基地址寄存器(Base Register)。它可作为存储器指针来使用; 寄存器ECX称为计数寄存器(Count Register)。 在循环和字符串操作时,要用它来控制循环次数;在位操作中,当移多位时,要用CL来指明移位的位数; 寄存器EDX称为数据寄存器(Data Register)。在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址。 在16位CPU中,AX、BX、CX和DX不能作为基址和变址寄存器来存放存储单元的地址,在32位CPU中,其32位寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑运算结果, 而且也可作为指针寄存器,所以,这些32位寄存器更具有通用性。 2、变址寄存器 32位CPU有2个32位通用寄存器ESI和EDI。 其低16位对应先前CPU中的SI和DI,对低16位数据的存取,不影响高16位的数据。 寄存器ESI、EDI、SI和DI称为变址寄存器(Index Register),它们主要用于存放存储单元在段内的偏移量,

快速入门单片机汇编语言

快速入门单片机汇编语 言 文档编制序号:[KKIDT-LLE0828-LLETD298-POI08]

快速入门单片机汇编语言 简要: 单片机有通用型和专用型之分。专用型是厂家为固定程序的执行专门开发研制的一种单片机,其程序不可更改。通用型单片机是常用的一种供学习或自主编制程序的单片机,其程序需要自己写入,可更改。单片机根据其基本操作处理位数不同可以分为:1位、4位、8位、16、32位单片机。 正文: 在此我们主要讲解美国ATMEL公司的89C51单片机。 一、89C51单片机PDIP(双列直插式)封装引脚图: 其引脚功能如下: P0口(—):为双向三态口,可以作为输入/输出口。但在实际应用中通常作为地址/数据总线口,即为低8位地址/数据总线分时复用。低8位地址在ALE信号的负跳变锁存到外部地址锁存器中,而高8位地址由P2口输出。 P1口(—):其每一位都能作为可编程的输入或输出线。 P2口(—):每一位也都可作为输入或输出线用,当扩展系统外设时,可作为扩展系统的地址总线高8位,与P0口一起组成16位地址总线。对89c51单片机来说,P2口一般只作为地址总线使用,而不作为I/O线直接与外设相连。 P3口(—):其为双功能口,作为第一功能使用时,其功能与P1口相同。当作为第二功能使用时,每一位功能如下表所示。 P3口第二功能

Rst\Vpd:上电复位端和掉电保护端。 XTAL1(xtal2):外接晶振一脚,分别接晶振的一端。 Gnd:电源地。 Vcc:电源正级,接+5V。 PROG\ALE:地址锁存控制端 PSEN:片外程序存储器读选通信号输出端,低电平有效。 EA\vpp:访问外部程序储存器控制信号,低电平有效。当EA为高电平时访问片内存储器,若超出范围则自动访问外部程序存储器。当EA为低电平时只访问外部程序存储器。 二、常用指令及其格式介绍: 1、指令格式: [标号:]操作码 [ 目的操作数][,操作源][;注释] 例如:LOOP:ADD A,#0FFH ;(A)←(A)+FFH 2、常用符号: Ri和Rn:R表示工作寄存器,i表示1和0,n表示0~7。 rel:相对地址、地址偏移量,主要用于无条件相对短转移指令和条件转移指令。 #data:包含于指令中的8位立即数。 #data16:包含于指令中的16位立即数。

OllyDbg入门完全教程(完美排版)

OllyDbg完全教程 目录 第一章概述 (1) 第二章组件 (5) 一、一般原理[General prnciples] (5) 二、反汇编器[Disassembler] (8) 三、分析器[Analysis] (9) 四、Object扫描器[Object scanner] (12) 五、Implib扫描器[Implib scanner] (12) 第三章 OllyDbg的使用 (13) 一、如何开始调试[How to start debugging session] (13) 二、CPU 窗口[CPU window] (14) 三、断点[Breakpoints] (14) 四、数据窗口[Dump] (15) 五、可执行模块窗口[Executable modules window] (16) 六、内存映射窗口[Memory map window] (17) 七、监视与监察器[Watches and inspectors] (19) 八、线程[Threads] (19) 九、调用栈[Call stack] (20) 十、调用树[Call tree] (21) 十一、选项[Options] (21) 十二、搜索[Search] (22) 十三、自解压文件[Self—extracting (SFX) files] (22) 十四、单步执行与自动执行[Step—by—step execution and animation] (23) 十五、Hit跟踪[Hit trace] (23) 十六、Run 跟踪[Run trace] (24) 十七、快捷键 (26) 十八、插件[Plugins] (29) 十九、技巧提示[Tips and tricks] (29) 第四章其他功能 (30) 一、调试独立的DLL[Debugging of stand—alone DLLs] (30) 二、解码提示[Decoding hints] (32) 三、表达式赋值[Evaluation of expressions] (32) 四、自定义函数描述[Custom function descriptions] (34)

反汇编 第二节 常用汇编指令

——啊冲 第二节常用汇编指令 说明:汇编语言也是一门语言,其指令相当的多,非常丰富,在此我只介绍几个常用的、简单的汇编指令,让大家与我一同入门。其实在超多的计算机知识领域里我和大家一样只是个学生而已。所以,我所要求的同学级别(本视频所针对的对象)是:有一点编程经验,对反汇编感兴趣、零基础的朋友。 堆栈操作指令PUSH和POP ?格式: PUSH XXXX ?POP XXXX ?功能: 实现压入操作的指令是PUSH指令;实现弹出操作的指令是POP指令. ? 加减法操作add和sub指令 ?格式: ADD XXXX1,XXXX2 ?功能: 两数相加 ?格式: SUB XXXX1,XXXXX2 ?功能: 两个操作数的相减,即从OPRD1中减去OPRD2,其结果放在OPDR1中.

调用和返回函数CALL和RET(RETN) ?过程调用指令CALL ?格式: CALL XXXX ?功能: 过程调用指令 ?返回指令RET ?格式: RET ?功能: 当调用的过程结束后实现从过程返回至原调用程序的下一条指令,本指令不影响标志位. ? 数据传送MOV 格式: MOV XXXX1,XXXX2 ?功能: 本指令将一个源操作数送到目的操作数中,即XXXX1<--XXXX2. ? 逻辑异或运算XOR ?格式: XOR OPRD1,OPRD2 ?功能: 实现两个操作数按位‘异或’运算,结果送至目的操作数中. ? 逻辑或指令OR ?格式: OR OPRD1,OPRD2 ?功能: OR指令完成对两个操作数按位的‘或’运算,结果送至目的操作数中,本指令可以进行字节或字的‘或’运算.

有效地址传送指令LEA ?格式: LEA OPRD1,OPRD2 ?功能: 将源操作数给出的有效地址传送到指定的的寄存器中. ?实际上,有时候lea用来做mov同样的事情,比如赋值: ?Lea edi,[ebp-0cch] ? 字符串存储指令STOS ?格式: STOS OPRD ?功能: 把AL(字节)或AX(字)中的数据存储到DI为目的串地址指针所寻址的存储器单元中去.指针DI将根据DF的值进行自动调整. ?说明:在VC的DEBUG版里经常用来为局部变量空间写上cccccccc指令 ? 比效指令CMP(CoMPare) ?格式: CMP OPRD1,OPRD2 ?功能: 对两数进行相减,进行比较. ?说明:经常与跳转指令相配合来形成循环或跳出操作 ? 跳转指令JXX ?JMP:无条件转移指令

相关文档