收藏 分享(赏)

第十二章 APO编程语言.doc

上传人:精品资料 文档编号:7533777 上传时间:2019-05-20 格式:DOC 页数:37 大小:134KB
下载 相关 举报
第十二章 APO编程语言.doc_第1页
第1页 / 共37页
第十二章 APO编程语言.doc_第2页
第2页 / 共37页
第十二章 APO编程语言.doc_第3页
第3页 / 共37页
第十二章 APO编程语言.doc_第4页
第4页 / 共37页
第十二章 APO编程语言.doc_第5页
第5页 / 共37页
点击查看更多>>
资源描述

1、第十二章 APO 编程语言这章是基本的、重要的;我不得不反复、仔细、认真的修改,即使啰嗦、也力求能完整说明。系统安全是随时要考虑到的,除了用户指令须是安全的、用户进程只能走在自己声明的变量空间上外;对文件操作也是要设置一系列权限。对文件的操作权限,我们是参照 UNIX、LIUNX;在实现上,做了一些简并和优化。APO 操作系统:包括内核方法库,用户的 API 方法库,公共通用方法库,日志、文件、数据库、网络等服务进程,实时进程支持,动态优先级的进程调度,一个进程最多 64K 个线程的线程优先级调度,信号、消息处理,GPU 的 4D 图形处理、显示,音频处理等等;APO 的指令代码量不会到4KW

2、,大约就是 4 千条指令吧。LINUX 有的功能、APO 都有,但在速度上要快得多,一些项目甚至要比 LINUX 快近百万倍。一、变量空间说明为了系统安全,用户是没法知道其变量空间在本地内存中的实际地址的;也不能使用指针来指向内存的实际地址。就类似,我们不知道地球挂在相对宇宙中心的什么位置一样?宇宙中心在那?我们是无法知道的。但在自己声明的变量空间上,可以使用寄存器作为相对偏移指针;如 D.A1.A2Ai.X.R1L.W,大对象空间 D 中的成员变量 A1 子空间中的成员变量 A2 子空间中的.。 。 。 。成员变量 Ai 子空间中的成员变量 X 子空间中的以寄存器 R1L 为指针的字变量位置

3、。类似,银河系中的地球的中国的广西省的以寄存器 R1L为县名指针的具体县位置。变量空间是靠我们声明的,你说多大就是多大了;是否能成功,那要看系统的运行情况。如果你声明 300GB 的变量空间,那么系统本地内存最多只是 128GB 的空间,显然、你会得到一个错误返回。对象的空间基本单位是行 E,理论上对象空间最大可以声明到 4GE = 32GW = 128GB。而对象空间下、或许有一大堆有层次、树状结构的成员变量,它们的大小要用 32 位表示、相对根对象的偏移也要用到 32 位来表示。对象空间下的某个成员变量可能是用位、或字符、或字、或双字来描述的,那么表示空间属性的行内编码,位需要 8 位、字

4、符需要 4 位、字需要 3 位。所以,描述一个变量空间需要 32 位的大小、32 位的偏移、10 位的根对象号(间接表示在本地内存中的位置) 、可能 8 位的行编码、可能 16 位的立即数赋值或 1 到 2 个的 6 位寄存器描述等等。所以,操作一个变量的指令码需要 3W 大小、耗时 3ns。1、空间分割变量空间分割成多个成员变量子空间,这是常见的;也可以说是合成吧,我们通常在一个表、或 C 语言结构、或数组、或向量、或集合、或类的属性表、或类的方法表中声明多个变量;在成员变量中又可以再分割下去,那要看需要。无论怎样,你只要给变量名字、声明其空间大小;在某个根对象中适合的位置声明;编译器总是能

5、知道你的变量在根对象空间中的相对位置和大小;但编译器也不知道根对象在本地内存空间中的具体位置。一个应用程序最多可以声明 992 个根对象空间;所有的变量空间位置都是相对于某个根对象空间的。类方法表 lf_tab 根对象有 32 个,0 是本类方法表、1-31 是程序引用的公共、或自己的方法类库 DLL;API 公共方法库是公开的、固定的、是无须安装就可使用的。线程类方法表 thread_lf_tab 有 128 个、为线程组 run()入口和长度。我们声明的静态根对象属性表 dx_tab(Di)有 64 个;而在代码中声明的、但动态分配内存空间的动态根对象可以有 768 个。2、静态变量空间在

6、进程开始运行时,申请内存分配的、由编译器指定的静态根对象空间;只有在进程完全退出时,才会释放掉。如果、你的变量是挂在某个静态根对象 Di 空间下的成员变量,那就是静态变量。要注意到、声明的静态变量空间在程序运行期间一直占据部分内存,直到程序退出时,才由系统释放。3、动态变量空间在程序的方法中、声明的、和动态分配内存 new()的变量是动态变量,属于动态根对象。动态根对象同样可以声明成复杂的、有层次树状结构的、有一大堆成员变量的结构空间。对于动态变量、当它们的引用计数为 0 时,会自动被系统回收、释放掉它们的空间。4、变量的操作在代码中都是用变量名来操作变量的空间,一个变量空间中的部分内容拷贝到

7、另一个变量空间中去,是由系统 API 中的 COPY 方法来完成的。变量的操作主要有:对变量空间中某个位置的内容进行寄存器、或 16 位立即数、或其中的一位的赋值;或某个位置的内容拷贝到某个寄存器中;或对变量空间中某个位置的位进行测试转移。某个位置有时,也可以用寄存器做指针。5、变量的编译说明在用户程序中,不管是动态、静态声明的对象,或字符串常量;它们在编译器的符号表中都有对应的 32 位大小、32 位相对根对象的偏移地址、所属的 10 位根对象号、空间性质:行内寻址(位 8 位、字符 4 位、字 3 位、行 0 位)项目。如下:BU3W STE / symbol table entry 符号

8、表项BU32 GDX; / 所属根对象变量/ GDX.31 static; 1、是静态编译的对象,0、是动态对象。/ GDX.30 gdxm; 1、本变量就是根对象,0、是根对象的成员变量。/ GDX.29-28 ladd; 行内寻址、空间性质:0、行,1、字,2、字符,3、位。/ GDX.9-0 gdxd; 根对象号。/ 行寻址模式时:/ GDX.27-10 0; 这些位为 0。/ 位寻址模式时:/ GDX.27-26 control; 指令模式:0、位赋值 0,1、位赋值 1,/ 2、位为 0 测试跳,3 位为 1 测试跳。/ GDX.25-18 0; 这些位为 0。/ GDX.17-10

9、 bitadd; 位地址。/ 字、字符的立即数寻址模式时:/ GDX.27-14 0; 这些位为 0。/ GDX.13-10 Zadd; 字符、4 位、字、3 位的行内寻址。/ 字、字符的寄存器寻址模式时:/ GDX.27-26 control; 指令模式:0、变量到寄存器,1、寄存器到变量,/ 2、变量的寄存器寻址后到寄存器,3、寄存器到变量的寄存器寻址后。/ GDX.25-14 RDiRNi; 表示是什么寄存器,R0H、R0L、R0、R1H-R31。/ GDX.13-10 Zadd; 字符 4 位、字 3 位的行内寻址。BU32 ROFF; / 32 位相对根对象的偏移地址。BU32 LE

10、NGTH; / 32 位的变量大小。这些变量值都是编译器知道的,我们可以用编译器方法获得变量的长度、偏移地址、对象号等。如:R1 = getdx(变量名字); 就得到了根对象号, R1 = getlen(变量名字 );就得到了变量的长度。要注意到,如果你声明的变量是 BU32 那就是 32、如果是 BU1W、或 BU1Z,或 BU1E、那都是返回 1。字符串用 BUnZ 声明,返回的就是字符串长度 n 了。也可以获得相对根对象的偏移地址,用 getoff(变量名); 实际上、编译器是根据你的方法从符号表中、赋值相应的 32 位数到你声明获得结果的寄存器;不外是编译成一条 32位立即数对寄存器的

11、赋值指令吧,2W、2ns。在方法中,你要变量的大小、或长度、或对象号做传入参数,那要写成 getlen(变量名字)、或 getoff(变量名)、或 getdx(变量名字)。如果参数直接写变量名,那编译器将是编译成一条 3W、3ns 的内部专用指令pointer;硬件总线控制器内部的专用寄存器 PITR 将是对象的实际地址、和 LENG 是大小。对于应用程序来说、除了会多耗 3W 的指令空间和 3ns 的时间、没什么用处;用户代码不在系统代码区域,读 PITR、LENG 会报错、被灭。6、操作根对象根对象空间可看作是一个位、或字符、或字、或行的线性空间,没有 32 位的偏移、也不需要 32 位的

12、大小(大小值已经在对象号对应的项里) 。只是 10 位的根对象号,空间单位性质说明 2 位(位、字符、字、行) ,行内寻址(位 8、字符 4、字 3、行 0) 。对象名就对应这根对象号,但有时候是不一定有名字的、只有根对象号,比如一些它方进程提交的动态对象;这时、编译器无能为力了。如果,一个网络进程完成了一个完整数据包的接收组装、将该数据包容器通过系统提交给相对应的用户进程;其过程是:1、使用用户进程的 pid 号、向系统申请一个用户进程的动态根对象号、并使其指针指向完整数据包、其大小值为完整数据包的大小。2、向用户进程发接收数据包消息,消息中含提交的用户进程的动态根对象号。3、用户进程使用该

13、动态根对象号操作数据包,完成后、回消息给网络进程。4、网络进程向系统释放该动态对象号、和数据包对象。不用名字操作变量空间的情形就类似,R1.A1.A0Ai.X.12.Z = 22;的情形;这时,编译器将把 R1 的低 10 位当作是根对象号、.A1.A0Ai.X.12 计算其 32 位的行偏移、.X 计算其空间大小、.12.Z 计算其空间性质放在 R1 寄存器的其它位、编译成一条 3W、耗时3ns 的寄存器对象号间接指令。还有一种方法是利用文件号,用户程序是使用 open 一个文件号给网络进程、就当网络进程是一个磁盘空间文件系统;但关联文件号的流容器并非用户进程提供,而是网络进程做关联。当收到

14、文件号已经关联到一个完整数据包流容器的消息时,用户进程只是使用文件号 fd、就可操作该完整数据包了。当操作完成后、用户进程就用 pid、fd 发相关消息回给网络进程;网络进程就可重新使用该流容器用于其它方面。当用文件号操作其关联流容器时,格式一定是 fd.XX.XXXX.N.Z/W/E;不能 Ri.XX.,也不能:变量名字.XX.;那样、编译器将无所适从。fd 是保留字、使用 fd.编译器才能正确编译成是用文件号操作关联流容器;否则可能会认为是操作根对象。fd.模式的指令是4W、4ns;对其流容器成员的操作可以赋值 32 位立即数。fd 是一个用户可以使用的专用寄存器,其实是有 2 个:fd、

15、fd1。用户的线程让步后,需要考虑保存你的文件号;因为 fd、fd1 是公用的。fd、fd1 实际上就是寄存器 R24H、R24L,注意啊,不要随便操作R24;那也是系统使用的寄存器。二、指令、方法使用简介APO 编程语言是基于汇编语言和面向对象编程。基本指令只有 6 种:赋值指令、BTX(位 X 测试为 1、或 0 转移)指令、查表跳转指令 switch(RN).、寄存器的移位与循环指令 S、寄存器的三操作数运算指令、调用与返回指令。所有的指令大小、除了32 位立即数赋值是 2 字、和含有对象、变量的指令是 3 字外;其它都是 32 位,一个字。指令执行时间,除了 2W 指令是 2ns、3W

16、 的是 3ns 外;其它指令都是 1ns。 应用程序只能使用 R0-R4,R8-R23 的 21 个寄存器作为高速的寄存器局部变量;其中 R0-R4 作为方法参数寄存器,R0 通常为返回结果寄存器。通常,子程序的形式用 C 语言表达就是函数;用所谓面向对象语言表达的是函数或方法。APO 使用的是汇编语言,通常用伪指令(一组指令的缩写形式宏)来描述调用指令 CALL;如:方法名称(参数 1,参数 2,参数 3,参数 4,参数 5); 由编译器翻译成相关的最多 6 条汇编指令。其实,参数 i 是需要对应写入寄存器 Ri(Ri = R0-R4) ;这就需要若干指令;以上的缩写编译器会自动展开成对应的

17、一组指令的。参数可以有一个或多个,或者没有;没有参数的形式:方法名称();编译后就是一条指令 CALL。方法是先压入 PUSH、再 Ri = 参数 i; 的;这样,返回时就能恢复调用前的 R1-R4。 返回的结果:数值可以写到寄存器 R0;也可以写到寄存器 R8-R31 或静态变量中去。 CALL是压入 H0 的 R0R4 及 PSR、PRR、PPC;而 RET 是弹出 R1R4 及 PSR、PRR、PPC。 R0是不被覆盖的! 所以,R1-R4 可看作是自动变量。指针或数据入口参数也可以先写入R8-R31;之后,再调用方法。注意:寄存器 R24-R31 是系统方法使用的局部变量;用户应用程序

18、使用时;应注意到调用系统方法时,它们可能会被改写。方法(子程序)的编写形式如下:方法名称:指令 1;指令 n;RET;或:方法名称一些方法的集合就构成了方法库,方法库是放在只读的保护区域;由内核管理。一些公共的方法库是常驻在保护区域的。用户进程的方法库是动态存在于保护区域,当用户进程退出时,如果用户方法库的引用计数为 0;就会使 用户方法库被踢出保护区域。方法库就是一个文件形式。所谓面向对象语言表达的接口概念其实就是指对象的一个方法库。CALL 指令用来调用一个方法; 此时,下一条指令地址 PPC 会被压入堆栈,是压入行寄存器 H0:R0R4 及 PSR、PRR、PPC;以备返回时能恢复执行下

19、条令, RET 指令用来从一个方法返回;之前 CALL 保存的下条指令地址会从栈内弹出到 H0 行寄存器中,RET 是弹出 H0 的 R1R4 及 PSR、PRR、PPC。程序转到 CALL 之前的下条指令处执行。调用方法格式:方法名称(参数 1,参数 2,参数 3,参数 4,参数 5);与 C 函数的区别:1) 、无须指明函数返回值类型;返回的值取决于方法或编程员的说明。2)、没有复杂的形参、实参、指针、Void、数组引用等说法;全看作是 32 位寄存器参数。你认为是什么样的参数,那是由你决定的。3) 、无须头文件、无须函数原型声明。4) 、除了寄存器变量,就只有你声明的静态变量。立即数可以

20、 8 位或 16 位一组用“.”号隔开。已经声明的变量,可直接代入寄存器相关位置;实际上,是变量的地址代入寄存器相关位置。如:方法 1(3, 5.5, ,6.0.1.5 ,AAA); 入口参数 4 个,写入寄存器 R0、R1、R3、R4; R2 不管;其中 R4 为变量 AAA 的地址。R0-R4 是方法内的自动变量,方法返回时被调用前的覆盖。通常是,在方法中,R0-R4 只是作为只读的入口参数;而输出结果可用寄存器:R8R31。在 APO 中,栈的用途除了 CALL,RET 就没有什么用了。APO 只有寄存器型自动变量、静态变量(代码中申请内存分配的动态变量,本质上还是静态变量) 。可以直接

21、:如,R17 = 89; 用户自定义;不一定非要编译器分配寄存器变量空间。毕竟,寄存器空间有限;自己分配更为清晰些。使用寄存器变量的好处是无须写变量声明等;如果需要更大的空间来使用,你只能申请内存分配的动态变量了;BUxE new(YYY); 就可得到 x 行的内存空间了,对该空间的初始化方法得自己编写了。YYY 的释放你无须考虑,YYY 一旦不用,系统会立即回收。最好,还是一开始就分配成静态变量并初始化了,省事。三、安全性1、变量与空间声明一个变量,实际上就是分配一个一定大小的存储空间;编译器会把变量名字翻译成该存储空间的相对逻辑地址。寄存器变量的地址是固定的实际地址,大小是 32位的位容器

22、;所以,无须声明;直接使用就行了。存储空间是有单位的,如 BU1 32 A; 声明变量 A 的空间是 32 个的 1 位数组,与 BU32 A; 声明变量 A 的空间是 32 位的位容器,与 BU1W A; 声明变量 A 的空间是 32 位字的位容器,与 BU2Z A; 声明变量 A 的空间是 2 个 16 位的字符位容器;它们的意义是一样的。变量空间的寻址,是应该用修饰符.Z、.W、.E 说明;比如 BU256 A; 那么 A.0 = 1,是变量 A 的第 0 个位的位地址内容?还是变量 A 的第 0 个字符地址内容?还是变量 A 的第 0 个字地址内容?还是变量A 的第 0 个行地址内容?

23、编译器通常认为是第 0 位。如果说 A.0.Z,那就清楚了,是变量 A 的第 0 个字符内容赋值为 1; A.3.W = 1, 就是变量 A 的空间以字为单位,是第 3个字地址内容赋值为 1。寄存器变量是 32 位的位容器;R3.0.Z 简写为 R3H 高半字;R3.1.Z 简写为 R3L 低半字。用户程序只是能操作自己声明的变量空间、和寄存器变量 R0-R4、R8-R31;所以,没有指针变量。指针操作,如(RX)、(变量)、在用户应用程序中是不允许的;编译器会报错;指针操作会带来风险。寄存器都是 32 位的,如 R2.230、R3.3.W、(R16)等等、编译器都是报错。但也可以分为高低 2

24、 个半字操作,如 R1H、R1L,和行寄存器方式 H1: R8-R15, H2: R16-R23, H3: R24-R31。要注意到 H3 行寄存器,在调用系统方法时,会被改写;所以,尽可能不使用 R24-R31。变量是有空间大小的,赋值操作不能超出其范围;否则编译器报错。2、变量寻址CPU 到本地内存间是 256 位数据总线、32 位的行地址总线(高 16 位为块号、低 16位是块中的行号) ;所以,CPU 到本地内存的读写是以行 E 为单位的。那么、变量的位寻址空间、字符寻址空间、字寻址空间、行寻址空间是如何实现呢?这时专门的总线硬件实现的,这时一种、读-修改-回写、的方法。先把变量所属的

25、行内容全部读入,再据指令码的寻址模式描述,来决定是修改或读取那一个位、或那一个字符、或哪一个字、或就是该行;如果是修改、那就要回写;如果只是把变量内容赋值到寄存器,那就不用回写。那是如何实现 A.B.C.5.W.H = 3;等指令? 我们知道任何一个变量都是或以对象、或以对象的成员的形式出现的。进程的 i 节点、对象头列表等等、都是属于系统管理的变量,用户是不能对系统变量进行直接操作的。A.B.C.5.W.H = 3 中,编译器是把整条语句翻译成 96 位的 3W 指令,其中 A 翻译成 10 位对象号,B、C、5.W.H 意思是 B 是 A 的字成员变量,C 是 B 的字成员变量,5.W.H

26、 是 C 的第 5 个字成员变量中的高半字;编译器只是把.B.C.5.W.H 翻译成相对于 A 的 32 位相对偏移行地址,和 4 位行内的字符地址,3 是 16 位的立即数,指令码 2 位。比如对象 A 的大小是 16E,B 的大小是 4E、偏移 A 是1E,C 的大小是 2E,偏移 B 是 1E;那么、编译器就能算出 C 对于 A 的偏移是:+ 1 + 1 = 2E。32 位的相对偏移地址就是行号,行内寻址编码对于字寻址就是 3 位行内字地址,对于字符寻址就是 4 位行内字符地址、对于位寻址就是 8 位行内位地址。.5.W.H 编译器就知道是行内字符寻址、行内寻址编码是 2*5 = 10,

27、即第 2 行的第 9 号字符。还有变量的 32 位大小、用于判断是否越界。对于变量X = D.A0.A1.Ai.B.3.Z,那么 D 是对象号,A0-Ai 是必须是以行为起始的对象、或表、或说变量,否则编译器可能计算会有错误。理论上,你可以声明 4GE 的大对象;在磁盘空间可能可以实现,但在只有 4GE 的本地内存空间是不可能的。对于每个进程,系统都分配有数据块,用来装进程的属性表等系统管理的全局变量。而当前进程的 32 位的对象头列表的基址(块地址、行地址)就放在专用寄存器A0;这个寄存器只能是进程成为当前进程时,由系统私有方法读写;任何非系统方法操作都异常中断。A0 是进程中所有变量(对象

28、)的基址,当执行指令 A.B.C.5.W.H = 3;时,(A0 + A 对象号)就得到了对象实际的块、行基址,和对象大小(用于硬件判断是否越界) ;以实际基址 + 32 位相对行偏移得到变量的实际行地址,并读入该行内容到总线硬件内的行缓冲寄存器,之后把数值 3 赋值到相应的行缓冲寄存器中的相应字符寄存器;最后,回写行缓冲寄存器的内容到对象的相应行内存。总耗时、12 个机器周期、3ns。使用(RN).n = 3;的寄存器指针模式,也能达到相同效果;耗时只是 1ns;但该方式是属于超级指令,只能系统方法使用;应用程序只能使用变量模式,行走在自己的变量空间中。如果要对 对象.变量赋值 32 位立即

29、数,那要先 RD = 立即数; 再: 对象.变量.W = RD; 要赋值对象.变量的一行;那么,先赋值 H2,再对象.变量.E = H2;对象号相对应的安装地址内容都是块号、行号;动态变量、对象、表、流容器等的首地址也是块号、行号;当操作到对象下的成员变量时,对象空间的首地址是基址(块号、行号) 、而成员变量可能是以对象空间为位、或字符、或字来定义的;这时、成员变量的相对偏移地址是 32 位的:对应位空间最多 4G 位,对应字符空间最多 4G 字符,对应字空间最多 4G 字。所以,要注意到、到达最终成员变量前的都应是行对象。如 D.A0.A1Ai.X.2.W,编译器编译 D 是对象号、A0-A

30、i 是以行单位的成员变量,最后的 X 是以字空间为单位的、范围最多 4GW;如 D.A0.A1Ai.X.5G.W,那编译器报错,X以字为空间、最多只有 4G 字,5G 字则超出范围。编译器实际上是先计算出A0.A1Ai.X 的相对 0 的偏移行地址(16 位的块号、16 位的行号) ;再计算.2.W、编译。对于应用程序是没有指针的、变量必须完整赋值、或被赋值;声明了变量,我们在程序内就直接用变量名就行了。如何计算、那就是编译器和系统的事情了。我们要做的就是声明一个个对象空间,并为之规划、起成员变量、对象名字;之后、编程时、用它们的名字通过指令、方法操作空间。3、安全性问题我的电脑满是病毒,很难

31、清除;360 等都没用。为修改这章,已经蓝屏好几次了。真的晕了,不就有时上下那种网站,就给毒得不清不楚。好了,我们得考虑下,病毒攻破系统的可能性。应用程序中的方法只能操控本程序中的变量,不能操控其它程序的变量;更不要说操控系统变量了。如何实现呢? R0-R4,R8-R31 的寄存器间相互赋值是没问题的,但对 R5(PSR)、R6(PRR)、R7(PPC)的赋值,问题就来了;我们不可能单纯依靠编译器的。其实,CPU 内是有硬件监控的,如果不是系统方法区(本地内存第 0、1 号数据块)的指令来对 R5-R7 赋值、或含有(RN)的指令,会产生一个攻击系统异常中断;在这个中断程序里,会发信号、终结相

32、应的非法进程,并报错;无须蓝屏。CPU 中有“方法调用”硬件监视器,CALL 时、新的 PPC 就是目的地,而(PSP).7.W中的 PPC 就是源地的下一条指令,即返回点。简单硬件监视源地、目的地;目的地是 0号数据块,那么需要源地不大于 1 号数据块。如果目的地是 1 号数据块 API,那么许可。0、1 号的方法是系统方法不可能去调用用户方法的,用户方法只能最多是调用大于、等于 1 号数据块 API 库中的方法;不能调用内核方法;违者异常侍候。API 中的方法可以调用 0 号数据块中的内核方法。通过 API 库隔离了内核,你可以调用 API 库、其它方法库;但不能调用到内核的方法。只是,能

33、间接的通过 API 使用到一部分内核功能。即使是想调用它方的私有库,那也要通得过一系列权限检查才行。1) 、病毒只能是应用程序形式,要冒充系统方法是行不通的;除非你自己把它编译到系统方法区中。那么,用系统级指令混入的应用程序病毒,也是不行;没运行在系统方法区的超级指令都是非法的,被灭。2) 、破坏其它进程,但应用程序只能行走在自己的对象、变量空间中;进程间只能通过信号、消息来互通;通过动态变量的提交来做大数据量的交换。进程的 i 节点、对象列表等保护性属性区、进程的方法区都是由系统来管理;当然,你可以调用公开的系统方法、和应用程序的方法;但这些方法同样是行走在应用程序自己的对象、变量空间中。当

34、然,i 节点中的一些属性、如文件名字等,还是可以调用系统方法来读写的;只要权限够。3) 、破坏文件数据,那你要有相应的权限才行;每次放出 open 一个文件的系统消息,系统都会检查你的权限,通得过才行。你要发出一个消息都得调用系统方法才行,没法去搞乱消息缓冲区。有你的消息,系统自会通知到你的相关线程、或过程。4) 、应用程序中的对象名、变量名、方法名、类名等,一旦编译后就不能修改;杜绝冒充。要修改只能重新编译。编译器的符号表、i 节点、进程的系统管理的不变的属性区、全部一起生成 CRC 校验码,所有名字的哈希值表等等,形成一个版本号小型 i 节点比对文件。当应用程序安装时,系统会作版本号对比(

35、 CRC 值对比,名字哈希值对比,公司签名、方法数、对象数、大小等等对比) ,符合才会通过注册。5) 、最后一招,引狼入室。通过网站引诱用户安装病毒程序;病毒运行后。1、想法感染其它进程,这在 APO 中几乎不可能。进程的方法区、基本属性区是固定的;APO 实现应用程序功能的代码量很少;即使要用到方法库.DDL 文件。你可能说会伪装一个.DDL 文件代替原来的,但别人的程序只会公开一部分公开方法啊;要通过系统验证也太难了。2、自动复制更多的病毒.exe 文件到其它目录,但在 APO 中,受到文件权限的限制太大了,对于自动复制程序文件的进程,日志防护文件会有详细的追根到底的记录。Windows

36、对于文件的保护很不够,就在它的目录下;我的电脑有一大堆病毒文件。删除了,又换个文件乱名像鬼一样出现。3、夺取最高权限,这难度是高;但病毒效果好。甚至可以利用最高权限,编译功能更大的病毒程序;抹掉痕迹,留下通过消息操作的后门。但 APO 中的日志防护文件是隐形的、在 FLASH 空间、最高权限也不能抹除;反汇编追踪也不行。最高权限的用户进程可读、不能写;除了私有的系统方法外,一写就关机。主人手动开机登录时,可以用另一个系统安装时的密码,来抢回最高权限。那么,被抢夺的那段时间里的一切,都会原形毕露。主人可以用还原命令,回溯到被抢前的状态。四、指令简介:一、赋值指令:1、寄存器、或 CPU 片内变量

37、赋值指令,除 32 位立即数外大小 1W、耗时 1ns。 1) 、位赋值:如 R3.11 = 0; YJMK.3.E.5.W.3 = 0; 2) 、16 位赋值:如 R4L = 11; YJMK.3.E.7.Z = 33; 等等。寄存器的 16 位赋值要指明高 H、低 L 半字。3) 、32 位赋值:如 R31 = 11; YJMK.3.E.9.W.W = 333;等大小 2W、耗时 2ns。4) 、行赋值:H2 = 0; 等; 行只有全 0,或全 1 赋值,只限于行寄存器。5) 、运算赋值:只能是寄存器变量,如:R3 = ALU, #5; 实际是R3 = R3 ALU, #5; 只能是 16

38、 位的立即数。ALU 有:ADD 加法 + 、ADC 带进位加法、SUB 减法-、SBC 带进位减法、CMP 比较、DADD 十进制调整、 BIC(!N and RD) 立即数求反后再“与” RD+、RD-; 等等,也可以。6) 、位段赋值:将一个寄存器的 x 开始的 x1 位赋值到另一个寄存器的 x2 开始处;可以设置为先对另一个寄存器清 0、或全 1 后进行。如:R1H.3-0 = R5.30-27, 0; 结果是R1H.3-0 就等于 R5 的 30-27 位,R1H.7-4 的位都是 0。2、根对象变量赋值指令,大小 3W、耗时 3ns。1) 、位赋值:A.B.C.9.W.3 = 1;

39、 A.R1H.W.6 = 0; R1H 是空间偏移指针等。2) 、16 位赋值:A.B.C.5.W.H = 3; M.D.R3.1.Z = 16;3) 、变量、寄存器相互赋值:R9 = A.B.R2.9.W; R11H = A.B.3.Z; C.9.W = R13; B.A.10.E = H3; 等。应注意到位容器的大小;否则会有截断。通常以寄存器变量大小为准。2、文件号 fd 的流容器变量赋值指令,大小 4W、耗时 4ns。1) 、位赋值:fd.B.C.9.W.3 = 1; fd.R1H.W.6 = 0; R1H 是空间偏移指针等。2) 、16 位赋值:fd1.B.C.5.W.H = 3;

40、fd.D.R3.1.Z = 16;3) 、32 位赋值:如 fd.3.E.1.W = 333;等4) 、变量、寄存器相互赋值:R9 = fd.B.R2.9.W; R11H = fd.B.3.Z; fd.9.W = R13; fd.A.10.E = H3;等。应注意到位容器的大小;否则会有截断。通常以寄存器变量大小为准。二、BTX(位测试为 X 转移)指令:如:BT0 R3.7, #N; 如果 R3 的第 7 位为 0 跳到 N 执行。BT1 D.A1.A0.A3.5.W.31, #N; 对象 D 的最终成员变量 A3 的第 5 字的 31 位为 1、跳到标号 N 执行。测试状态寄存器 PSR

41、的位后的通用指令,左右 2 种写法都可以。JEQ/JZ 标号; 零位被置时转移到标号语句 等于时程序跳转 BT1 PSR.Z,标号; JNE/JNZ 标号; 零位复位时转移到标号语句 不等时程序跳转 BT0 PSR.Z,标号;JC/JHS 标号; 进位位被置时转移到标号语句 大于或等于时程序跳转 BT1 PSR.C,标号;JNC/JLO 标号; 进位位复位时转移到标号语句 小于时程序跳转 BT0 PSR.C,标号;JN 标号; 负位被置时转移到标号语句 为负时程序跳转 BT1 PSR.N,标号;JNN 标号; 负位被清零时转移到标号语句 大于或等于时程序跳转 BT0 PSR.N,标号;JV 标

42、号; 溢出位被置时转移到标号语句 BT1 PSR.V,标号;JNV 标号; 没有溢出时转移到标号语句 BT0 PSR.V,标号;JCZ 标号; C 置位,Z 清零时转移到标号语句 大于时程序跳转 BT1 PSR.CZ,标号;JZC 标号; C 清零, Z 置位时转移到标号语句 小于或等于时程序跳转 BT0 PSR.CZ,标号;JL 标号; N .xor. V = 1 时转移到标号 带符号小于时程序跳转 BT1 PSR.NV,标号;JGE 标号; N .xor. V = 0 时转移到标号 带符号大于或等于时程序跳转 BT0 PSR.NV,标号;JGT 标号; Z 清零且 N 或 V 置位, 或

43、N 清零、V 清零 带符号大于时跳转 BT1 PSR.GT,标号;JLE 标号; Z,或 N 置位且 V 零, 或 N 零且 V 1 带符号小于或等时跳转 BT0 PSR.GT,标号;JMP 标号; 无条件转移到标号语句 BT1 PSR.B1,标号;可以结合比较指令、来进行跳转时,可使用类 C 格式。比如:if A = 3 goto N; 等等。2 条指令合一,编译时会展开的。2W,2ns。程序状态寄存器 PSR = R5:31 29 28 27 26 25 24 23 22 21 20 19 18 17 16 13 12 8 7 0N Z C V CZ ZC LT GE GT LE B1 Y

44、J IN OUT 保留 执行标志 中断号N: 负号置 1 标志。 为负数NN: N = 0。 非负数,大于或等于Z: 结果为 0 置 1 标志。 相等(EQ)NZ: 结果为非 0,Z = 0。 结果非 0 或不等 NEC: 进位置 1 标志。 大于或等于(或 HS)NC: 无进位,C = 0。 小于 LOV: 溢出位置 1 标志。NV: 没有溢出, V = 0。CZ: C 置 1、结果非 0(Z = 0) 。 大于 HIZC: C = 0, 或 Z = 1。 小于或等于 LS LT: N XOR V = 1;N != V。 带符号小于 LT GE: Z XOR V = 0;N = V。 带符号

45、大于或等于 GEGT: Z = 0,N 或 V 置 1;或 N = 0、V = 0。 带负号大于 GTLE: Z 置位,或 N 置位且 V = 0;或 N = 0, V = 1。带符号小于或等于 LEB1: 为 1。 总是 1, AL三、查表跳转指令: switch(RN).;有时候,一个方法有 n 个分支,n 值在寄存器 RN;这样使用查表跳转指令,就会据 RN寄存器中的值而进入到正确的分支了。RN 为: R0-R4,R8-R31 中的一个。RN 是一个 16 位或 32 位寄存器整形变量,可以从表达式得到。这类似于 C 语言switch()、Case 的情形。四、移位与循环指令 S:只能是

46、寄存器变量S RD, RN, #N; S 为下列之一,N 为移动的最多 32 的位数。逻辑左移(变进位)LSR(C);算术右移 S(变进位)ASR(C); 循环右移(变进位)ROR(C);连进位一起循环右移 RRX;如:LSLC R1, R3, #6; R1 = R3 C 6,即 R1 = R3 左移 6 位,高位进 C。移位与循环指令也可以写成:RD = RN S N;五、三操作数运算指令:只能是寄存器变量RD = RN1 ALU RN2 S #N; / RN2 移位或循环 N 位后与 RN1 运算的结果存放到 RD。六、调用与返回指令:调用 CALL 则是直接写方法名,方法返回是 RET。

47、如果要做浮点运算、或更多的其它功能就要用到系统库里的方法了;APO 语言就7 种基本指令。硬件模块的专用指令在用到再说,内核编程则还包含一些指针操作的指令。五、面向对象编程面向对象编程在上一章已经介绍很多,这里只是举一些例子。例子 1:BU1W 100 A; / 数组变量 A 的成员都赋值为其下标。数组成员赋值方法() / 指令数 7W,运行时间:502ns。R1 = 0;L1:A.R1 = R1;/ 如果已经声明 A 是字数组,A.R1.W.W 可简写为 A.R1, 2W,2nsR1+;if R1 != #100 goto L1;RET汇编语言清晰、简单。可能有人会说,这么简单就要 6 行代

48、码;其实不然,一些高级语言编译成汇编码,会远超过这里的。汇编语言,指令的空间、时间都可明确掌握、底层清晰;根本不是别的语言可以取代的!其实,简单的东西需要复杂的实现;复杂的东西只是简单的代码。这就是我们的真实世界规律!例子 2:排序1、不带序号的数的位图式排序先介绍多功能硬件模块的比较指令 CMP 与位查询指令 BIX。硬件模块的 256E,可以分成 2 部分:输入 128E,输出 128E;如果输入 128E 中符合条件的结果全部给出在输出,那么标志 PSR.IN 置位,请求再输入 128E;如果输出 128E 中的结果满,那么标志PSR.OUT 置位,请求读出结果。这样,就无须多次启动 S

49、S1。对于范围在 64K 以内的无序数列,我们可以构建一个 64K 位的位图变量;让数列值映射到位图变量中的相应位;再利用多功能硬件模块的位查询指令 BIX,很容易就能得到按小到大的有序数列;而且速度极快。对于超过 64K、大小为 x 的无序数列,我们都可以构建有 n 个 64K 位的位图变量;让数列映射到位图变量中的相应位;之后,使用同样的方法进行。BU16 X M;/ 声明一个 16 位的无序数组变量 M、和装排序后结果。BU64K WTKJ = 0;/ 声明一个位图变量,内存空间 256H;编译器初始化为 0范围 64K 内无序数列排序()/ 占用:32W;耗时最大约:605usR2 = getlen(M);/ 编译器方法,32 位立即数赋值指令、2W、2ns。/ 获得变量 M 的大小到 R2 寄存器。类似的、R3L = getdx(M);是获得对象号等/ R1 = getoffadd(M);是获得 M 的

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报