Hallo Word

chenjunlin & blog

汇编基础学习笔记

x86架构通用寄存器(32位的x86架构和64位的x86_64架构) x86_64架构由amd公司推出,因此又叫amd64架构,64位架构是基于32位架构扩展的 32位架构的x86处理器具备8个32位的通用寄存器,可通过名称来引用这8个寄存器,分别为EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI EAX的低16位可以被单独使用,引用名称叫AX(高位是左边位,低位是右边位),AX又可以被分为高8位的AH和低8位的AL 实质上EAX,ECX,EDX,EBX都可以被拆开使用,ECX的低16位叫CX,CX又可以被分为高8位的CH和低8位的CL EDC的低16位叫DX,DX又可以被分为高8位的DH和低8位的DL,EBX的低16为叫BX,BX又可以被分为高8位的BH和低8位的BL ESP,EBP,ESI,EDI的低16位也可以被单独使用,但是没有8位的,这低16位名称分别是SP,BP,SI,DI EAX寄存器被乘法和除法指令自动调用,因此又叫累加寄存器 ECX被LOOP(循环)指令调用为循环计数器 ESP被用于寻址栈上的数据,ESP始终指向栈顶,因此又叫栈指针寄存器 ESI和EDI又叫变址寄存器,变址寄存器引用的是内存地址,ESI指向内存源地址,EDI指向目的地址 EBP叫帧指针寄存器,被用来引用栈上的函数参数和局部变量 除了通用寄存器还有EFLAGS标志寄存器,EIP指针寄存器(这个非常重要,因为其引用的是下一条要被指向的指令的地址,注意:并不能直接通过名称来说调用,只能通过CALL之类的间接修改)等等 64位架构(通用寄存器为16个,并且是64位的,而且每个都可以低8位,16位,32位单独使用) EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI的64位是R开头的,其他和32位架构是一样的,64位架构的内存地址也是64位的 x86汇编指令(通常是由一个操作码(opcode)和0到多个的操作数(operand)组成) 整数加减指令(ADD指令(有2个操作数,分别是目的操作数和源操作数,ADD指向将这2个操作数的值相加,将结果存放在源操作数中,源操作数可以是寄存器,内存,目的操作数要满足可写条件,因此也可以是寄存器,内存,但是不能同为内存))和SUB指令(和ADD指令一样,但是是将结果存放在目的操作数中)) ADD指令:ADD EAX,32 (将EAX寄存器的值加上32,并且将结果存放回EAX寄存器中) SUB指令:SUB ESP,32 (将ESP寄存器的值减去32,并且将值存放回EAX寄存器中) 数据传输指令(x86架构有多个数据传输指令,这里是MOV指令) MOV指令用于寄存器之间和寄存器和内存之间传输数据使用,MOV指令将源操作数复制到目的操作数中,例如MOV EDX, 666 (将数值666存储在EDX寄存器中) x86架构内存寻址:displacement(位移,可以在指令中直接得到内存的偏移量,也就是位移,这个位移表示距离操作数的直接偏移量),base(基址,内存地址存储在通用寄存器中),index(索引,注意ESP寄存器不能用于索引),scale(比例因子,用于索引相乘,是固定值,可取值1,2,4,8) 内存最复杂的地址计算公式:base+(index*scale)+displacement base和index,displacement都可以随意组合,也可以不存在,如果不使用index,就不需要使用scale了,scale只为index服务,index和scale被用于寻找数组地址和多维数组 入栈和出栈指令(PUSH和POP指令) PUSH指令只有一个操作数,就是需要入栈的源操作数,这个指令可以将ESP寄存器向下移动一个位,并且将源操作数复制到ESP寄存器指向的内存处,例如:PUSH EAX POP指令也是只有一个操作数,就是用来接收数据的目的操作数,POP指向会将ESP寄存器指向的内存处的值复制到目的操作数中,并且将ESP寄存器向上移动一个位置,例如:POP EAX 分支跳转指令(JMP指令) JMP指令只有一个操作数,这个操作数可以是内存,寄存器或者立即数,通过这个操作数来给出需要跳转的目的地址,例如 JMP EAX 过程调用指令(CALL指令) 高级语言的函数在汇编叫过程,CALL指令只有一个操作数,是过程的起始地址,例如 CALL EAX 分支跳转指令和过程调用指令的区别是,分支跳转指令不会记录返回地址,这个返回地址是CALL指令之后的下一条指令的地址,CALL指令会将返回地址入栈,然后跳转到目的地址执行 子过程执行完成通过RET指令返回,RET指令会在栈上弹出返回地址,并且跳转到该返回地址上继续执行 内存分页机制 线性地址 在内存分页模式中,应用使用的地址就叫线性地址,由MMU(menorymanagement unit)基于页表来映射转换为物理地址 在内存分页模式未出现之前,应用是直接访问物理内存的,应用具备读写全部物理内存的权限,因此可能会覆盖其他应用的数据,而80386架构出现,出现了保护模式,使用内存分页来通过特权级和进程地址空间来进行隔离 进程地址空间隔离是通过进程独立性页表来完成的,每个进程实现的地址空间是不同的,避免影响到其他进程 80386两级页表 80386架构的线性地址为32位,因此可寻4GB大小的内存空间(4096),地址总线也是32位,因此也是只能寻找4gb大小的物理内存,而且分页机制也将每个物理内存的页面的大小设为4096字节 一个页面大小为4096字节,地址总线为32位,因此一个页面可存储1024个物理页面地址,80386页表的第一页面是目录页面,物理内存地址存储在CR3寄存器中,可通过该目录页面来查找第二页面的1024个物理页面地址 MMU将32位的线性地址,低12位是页内偏移,然后的低10位是页表的索引,最后的高10位是页面目录索引,页内偏移的取值范围为0到4095,页表索引和页面目录索引的取值范围为0到1023 80386线性地址转换到物理地址的过程:先从CR3寄存器中获取页目录的物理地址,然后选择一个页表,在到页表索引中,找到页面的物理地址,最后通过页内偏移量来得到实质上的物理地址 PAE三级页表 80386架构的每个进程可使用4gb的线性地址空间,但是操作系统会将4gb的地址空间划分成用户空间和内核空间,为了解决内存空间不够使用,英特尔公司推出了物理地址扩展技术(PAE,PhysicalAddressExtension) PAE将地址总线扩展到36位,因此可寻找64gb的物理内存,但是线性地址依然是32位的,为了解决32位线性地址支持36位的物理地址映射,MMU页表映射机制进行了调整,一个页面只能存储512个地址 PAE的32位线性地址是,高2位是页目录指针索引,后面9位是页目录索引,再后9位是页表索引,最后12位是页内偏移 x64四级页表 因为PAE技术并没有扩展线性空间,32位的地址宽度不够使用了,AMD公司基于x86架构扩展而出的x64架构,x64架构的寄存器宽度是64位的,但是线性地址只使用了48位,但是也足够了,因为可以寻高达256TB的内存空间地址,具体可寻多少物理内存空间,取决于地址总线的宽度 x64架构,在PAE的基础上扩展了页表为4级,而且每个页面的大小是4096字节,高9位是页目录指针表,后9位是页目录指针,再后9位是页目录,然后9位是页表。最后12位是页内偏移量 虚拟内存 进程是以内存页面为单位向操作系统申请内存的,现代操作系统中会对申请的内存空间进行记录,并不会马上分配,而是等到该进程真正访问该内存空间是才会分配物理页面并且进行映射,然后恢复中断程序,如果进程访问了没有映射的内存空间,会被操作系统进行page fault处理,操作系统通过page failt handle进行检查内存空间分配记录 物理空间不够分配时,操作系统可以将少使用的物理页面写入到磁盘交换分区(Swap分区)中,将空出来的页面给需要的进程使用,注意:当在磁盘交换分区中内存页面被访问了,也会触发page fault处理,操作系统通过page failt handle来将磁盘交换分区的内存页面加载回内存中...

2022-11-20 · 1 min · Me

Deno js运行时环境学习笔记

Deno是基于V8引擎,使用Rust构建的JavaScript & TypeScript 运行时环境,天生支持TypeScript,并且有安全模式(默认情况下无法获取网络,文件系统,环境变量等权限,当然也可以开放),Deno的作者是Nodejs之父Ryan Dahl,构建的原因是解决Nodejs的缺陷,例如模块的安全性(Node运行时的权限很高,缺乏模块的安全运行),Deno的模块化选择了ESMoule标准,而且具备浏览器的api,例如window全局变量,支持onload,onunload等事件函数,支持fetch,Web Workers等标准,异步操作返回采用Promise,支持await Deno不使用node_modules与package.json的包管理机制,而是采用下载编译的机制,并且存在缓存,模块更新通过更新缓存来完成 Deno有个特殊的功能,就是可以从网络上导入模块 安装 Linux curl -fsSL https://deno.land/install.sh | sh 或者 windows iwr https://deno.land/install.ps1 -useb | iex 也可以通过scoop安装 scoop install deno 作为Rust构建的,当然也支持Cargo包管理器安装 cargo install deno –locked 或者通过单一的可执行文件来安装(我采用这个方式,再配置一下Path环境变量就是可以了,windows选择deno-x86_64-pc-windows-msvc) https://github.com/denoland/deno/releases 检查是否安装完成 deno –version 第一个例子 import DFetch from "https://deno.land/x/dfetch/mod.ts" DFetch.get("https://xiaochenabc123.test.com").then((response) => { console.log(response) }) 运行 deno run .\index.ts 它会向你询问进行网络请求,是否允许,可通过–allow-net默认运行,例如:deno run –allow-net .\index.ts 第三方库通过https://deno.land/x查找 权限 –allow-env,允许访问环境变量,可指定环境变量列表,通过逗号分隔 –allow-hrtime,允许高分辨率时间测量 –allow-net,允许网络访问,可指定网络地址列表,通过逗号分隔 –allow-ffi,允许加载动态库,动态库不是安全运行的 –allow-read,允许读取,可指定读取文件列表或者目录,使用逗号分隔 –allow-run,允许运行子进程,这个子进程不是安全运行的,可指定子进程列表,通过逗号分隔 –allow-write,允许写入,可指定写入文件列表或者目录,使用逗号分隔 -A 或者 –allow-all 允许全部权限 VsCode插件deno deno内置工具 安装模块...

2022-11-11 · 1 min · Me

计算机图形学学习笔记

计算机图形学(Computer Graphics,CG)是研究图形表达,生成,处理与显示的学科 通过数学算法将二维,三维图形转换成计算机显示器的栅格,例如向量,行列式,矩阵算法等等 图形学历史 1950年,MIT诞生第一个图形显示器(用于Whirlwind(旋风)电子管计算机显示图形),CRT显示器 Whirlwind电子管计算机设计之初是美国空军训练飞行员,半自动地面防空系统(SAGE) 应用CRT和光笔 1958年,双人网球 1960年,William Fetter(威廉﹒费特),创造‘计算机图形学’名词,计算机图形学先驱 1961年,史帝夫﹒罗素(Steve Russell),spacewar游戏 1962年,皮埃尔·贝塞尔(Pierre Bézier),贝塞尔曲线(Bézier curve),绘制曲线 1962年,伊凡·苏泽兰(Ivan Sutherland),Sketchpad绘图应用,计算机图形学之父 1963年,Force, Mass and Motion,https://techchannel.att.com/play-video.cfm/2012/8/20/AT&T-Archives-Force-Mass-Motion 1968年,Ivan Sutherland创造“达摩克里斯之剑”头盔显示器 1968年,Arthur Appel 提出光线投射算法 1973年,Bui Tuong Phong,发明phong shading(Phong着色法) 1974年,Speed Race游戏,第一款赛车游戏 1977年,3D core Graphics System,图形学标准 1980年,NEC µPD7220 GPU,支持1024*1024的显示,普及民用 1996年,Krishnamurthy与Levoy提出法线贴图(Normal Mapping) 1995年,Directx 1.0 1997年,OpenGL 1.1 1999年,Nvidia,Gefprce 256 GPU

2022-11-08 · 1 min · Me

WebSocket学习笔记

HTTP1.1协议实质上就是半双工信道,无法同时发送数据和接收数据,而且HTTP连接必须是客户端发起,由服务器来进行处理响应,只有HTTP2.0才是全双工信道(不需要等待响应,就可以发送第二个报文) WebSocket是全双工信道,而且还支持服务端主动发送数据给客户端,是服务器推送技术(还是需要客户端发起连接) WebSocket协议是应用层协议,而且是建立在TCP协议上,端口也是使用443和80,握手使用HTTP协议,浏览器不会限制WebSocket的同源 WebSocket客户端配置 WebSocket构造函数,用来创建WebSocket实例 const ws = new WebSocket(‘ws://127.0.0.1’) WebSocket.readyState实例具备4种状态,该属性是只读的,用来表示连接WebSocket服务端的状态,分别是:0(正在连接),1(连接完成并且可以通信),2(连接正在关闭),3(连接已经关闭或者连接失败) WebSocket.onopen是指定连接成功后执行的回调函数 WebSocket.onerror是指定连接失败后执行的回调函数 WebSocket.onclose是指定连接关闭后执行的回调函数 WebSocket.onmessage是指定从服务器获取信息时执行的回调函数 可以指定WebSocket.binaryType来指定传输的数据类型,数据类型有2种,分别是blob和arraybuffer 客户端配置例如: const ws = new WebSocket('ws://localhost:8080') ws.onopen = () =>{ console.log("连接中") ws.send('hallo word') // 向服务端发送数据 } ws.onerror = () =>{ console.log('连接失败') } ws.onmessage = (evt) =>{ console.log('连接成功,正在获取数据') if(typeof evt.data === String){ console.log('hallo'+evt.data) }else if(evt.data instanceof ArrayBuffer){ let data = evt.data console.log('数据:'+data) } ws.close() // 手动关闭连接 } ws.onclose = () =>{ console.log('连接已关闭') } 还有WebSocket.bufferedAmount属性,也是只读,用于返回WebSocket..send没有发送到服务端的数据的字节数,为0表示全部数据已传输完毕 WebSocket.url属性可以返回WebSocket实例的URL绝对路径,只读...

2022-11-05 · 2 min · Me

简单使用Element Plus组件库

Element Plus是基于vue3开发的组件库,而Element使用vue2开发的组件库 安装Element Plus npm install element-plus –save 或者 yarn add element-plus 导入Element Plus import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' 按需导入 安装插件 npm install -D unplugin-vue-components unplugin-auto-import 如果是使用Vite则配置vite.config.ts文件 导入并且启用插件 import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' ... plugins: [ AutoImport({ resolvers: [ElementPlusResolver()], }), Components({ resolvers: [ElementPlusResolver()], }), ], 这个组件库还支持module导入的方式手动按需使用,例如: <template> <el-button>I am ElButton</el-button> </template> <script> import { ElButton } from 'element-plus' export default { components: { ElButton }, } </script>

2022-11-03 · 1 min · Me