当前位置: 首页 > news >正文

开发网站需要用到的专业技术知识百度竞价排名推广

开发网站需要用到的专业技术知识,百度竞价排名推广,windows软件开发,湖州公司做网站写在最前面#xff1a;这一篇是UC Berkeley的CS61C的笔记#xff0c;根据我自己的理解进行学习记录#xff0c;其中贴的一些图片来自于课程PPT。 了解汇编之前#xff0c;我们需要先了解为什么需要汇编#xff1f;以下是我的理解#xff1a; 机器执行的命令都是些二进制… 写在最前面这一篇是UC Berkeley的CS61C的笔记根据我自己的理解进行学习记录其中贴的一些图片来自于课程PPT。 了解汇编之前我们需要先了解为什么需要汇编以下是我的理解 机器执行的命令都是些二进制的机器码我们需要对机器进行编程需要记住这些机器码这是对于程序员很不友好的所以前人就用一些汇编指令取替代这些机器码代码写完之后再使用编译器生成这些机器码所以汇编是为了简化编程而创造出来的。 汇编代码一般使用.S结尾表示source file汇编翻译出的机器码用.o结尾表示machine code object file链接器链接生成的结果以.out结尾表示是最后的生成结果。 文中的rd是register destination的缩写意为目标寄存器rs是register source的缩写意为源寄存器。 1 算数运算与逻辑运算指令 NumArithmetic / logicmeane.g.1add加法运算指令add rd, rs1, rs22sub减法运算指令sub rd, rs1, rs23and与运算指令and rd, rs1, rs24or或运算指令or rd, rs1, rs25xor异或运算指令xor rd, rs1, rs26sllshift left logical 逻辑左移运算指令sll rd, rs1, rs27srlshift right logical 逻辑右移运算指令srl rd, rs1, rs28srashift right arithmetic 算数右移运算指令sra rd, rs1, rs2 这是一组是运算指令1-2是算数运算指令3-8是逻辑运算指令。 算数运算指令比较简单这里以加法运算指令为例 a b c; add rd, rs1, rs2 - # a rd, b rs1, c rs2add rd, rs1, rs2的意义就是将寄存器rs1的值加上寄存器rs2的值最后存储到目标寄存器rd中。减法运算指令同理。 接下来看逻辑运算指令 以逻辑左移指令为例 sll x11, x12, x13 # x11 x12 x3以上指令的意义是将x12左移x13位存储到x11当中右移运算符srl使用方式相同。 sra算数移位运算符指的是移位后空出的bit用符号位填充 1111 1111 1111 1111 1111 1111 1110 0111 -25 srai x10, x10, 4 1111 1111 1111 1111 1111 1111 1111 1110 -2这里要注意算数移位运算并不等于直接除以2。 首先要注意的是RISC-V中是没有NOT指令的 2 immediate NumImmediatemeane.g.1addi加法运算指令addi rd, rs1, imm2andi与运算指令andi rd, rs1, imm3ori或运算指令ori rd, rs1, imm4xori异或运算指令xori rd, rs1, imm5sllishift left logical 逻辑左移运算指令slli rd, rs1, imm6srlishift right logical 逻辑右移运算指令srli rd, rs1, imm7sraishift right arithmetic 逻辑右移运算指令srai rd, rs1, imm 这一组指令可以看作是第一节的扩展第一节中的指令是将两个寄存器中的值做运算这一节中的指令同样是做算数运算或者是逻辑运算不同的是这一组指令用于常数计算。 为什么要单独出一组常数计算的指令呢这是因为常数相加非常常见如果从内存加载一个常数可能会消耗更多的时间用更多的寄存器直接用一组专用的指令可能会让执行速度变得更快。 以addi为例 a b 10; addi rd, rs1, 10 - # a rd, b rs1addi rd, rs1, imm的意义就是将寄存器rs1的值加上常数imm最后存储到目标寄存器rd中。 如果遇到a b汇编应该怎么写呢a b可以看作是a b 0但是这里我们不用addi而是用add addi rd, rs1, x0这里的x0表示寄存器该寄存器接地保存的值始终为0。 接下来有一点要注意这一组指令中并没有看到有subi当我们要用到立即数减法时编译器会帮我们转化为负数再使用加法这样做可以简化ALU单元的设计 a b - 9; addi rd, rs1, -93 Load/Store NumLoad/Storemeane.g.1lwload word 加载四字节指令lw x10, 12(x15)2swstore word 存储四字节指令3lbload byte 加载一字节指令4sbload byte 存储一字节指令5lbuload byte unsigned 加载一字节无符号数 我们调用汇编指令add sub来做运算但是运算所要的数据还在内存当中我们要如何将这些数据从内存加载到寄存器呢运算完成后如何将数据重新写到内存呢这就是这组组汇编指令的所能完成的事情。 lw用于从某个地址加载数据sw用于将数据存储到某个地址。接下来举例看看lw sw应该如何使用 int A[100]; g h A[3]; - lw x10, 12(x15) # x15表示数组A的地址 add x11, x12, x10 # g g A[3]我们首先要拿到数组A的地址然后根据偏移量以byte为单位获取到需要读取的地址这里要读取A[3]需要向后偏移12bytes调用lw指令加载数据最后完成计算。 如果我们要把计算得到的结果存储在A[10]中要如何处理呢 sw x11, 40(x15)计算目标地址与基地址的偏移量接着调用sw就好了。 使用lw sw时我们需要知道每次读取或者写入都是以四字节为单位32bit数刚好对应32bit寄存器因此符号位在读取、写入过程中可以保留。 RISC-V还提供了加载、存储一个字节的指令lb wb每次读取和写入都是一个字节使用方法和lw sw类似。但是这里就会有问题了当把一字节的数据从内存拷贝到寄存器时这一字节的数据只占用了寄存器的8bit那其他24bit3byte怎么办呢都填0吗有符号位要怎么办 这里的做法是将符号位上的数填充到前面的3bytes里这被称为符号扩展。 但是我们并不是每次都要做符号扩展比如加载一个无符号数据就不需要扩展所以还有一个指令lbu用这个指令做加载就不会执行符号扩展直接用0填充其他的三个字节。要注意是没有sbu 的这是因为从寄存器存储一字节到内存时这一字节的最高位本身就是符号位了。 4 Branch NumBranching/Jumpsmeane.g.1beqbranch if equal 等于beq rs1, rs2, L12bnebranch if not equal 不等于3bgebranch if greater than or equal 大于等于4bltbranch if less than 小于5bgeubge的unsigned版本6bltublt的unsigned版本7j(伪指令)jump 跳转j label 这一组是分支指令上面的1-6是条件分支指令需要通过比对值来控制代码执行流程这一组指令的最后一个参数是跳转标签Label7-9是非条件分支指令执行到这些命令时总是会跳转。接下来一起看看例子 如果我们要判断两个值是相等然后再去执行对应操作我们应该使用什么指令呢 if (i j)f g h; -bne x13, x14, Exitadd x10, x11, x12 Exit:可以看到我们用的时bnebne x13, x14, Exit的意思是如果不相等则跳转到Exit。为什么不用beq而是要用一个相反的指令呢我们尝试写一下 beq x13, x14, Branchj Exit Branch:add x10, x11, x12 Exit 从上面我们可以看到如果条件不成立跳过add指令会麻烦许多所以判断时用相反的指令会更加简洁。 接下来再看一个if-else的例子 if (i j)f g h; elsef g - h; -bne x13, x14, Elseadd x10, x11, x12j Exit Elsesub x10, x11, x12 Exit:这里有一点要注意不能忘了退出指令另外是没有ble 的如果需要判断小于等于可以通过是否大于来判断。 接下来的例子更复杂一点我们如何使用条件分支指令实现for / while 循环呢 int A[20]; int sum 0; for (int i 0; i 20; i)sum A[i]; -add x9, x8, x0 # x9A[0]add x10, x0, x0 # sumadd x11, x0, x0 # iaddi x13, x0, 20 # Loop:beq x11, x13, Donelw x12, 0(x9) # A[i]add x10, x10, x12 # sum A[i]addi x9, x9, 4 # A[i1]addi x11, x11, 1 # ij Loop Done:5 Pseudo-instructions 伪指令指的是一些常用汇编指令的替代例如 mv rd, rs addi rd, rs, 0 li rd, 13 addi rd, x0, 13 nop addi x0, x0, 0 ret jr ra j jal x0, Label 6 Function Call 这一组指令用于支持函数调用了解指令前先来了解程序是如何执行的。 我们的汇编代码经过编译器翻译后会生成二进制的目标文件目标文件中的数据就是一条一条的指令。程序执行时会将这些指令一条一条加载到内存中对应的程序区所以这些指令也是有对应的地址的。CPU中有一个特殊的寄存器Program Counter(PC)程序计数器里面存储的是下一条指令的地址一条程序执行完成PC会更新其保存的地址默认是增加4字节来指向下一条指令因为RISC-V中的所有指令都是32bits。PC中的地址更新时也会有其他情况比如说上面的j指令或者这一节将会了解的函数调用相关指令PC的地址将会更新到指定内存地址。 6.1 相关指令 函数调用中的一些约定 函数调用过程中使用a0-a7(x10-x17)argument register这8个寄存器来传递参数其中两个a0-a1用于返回参数寄存器x1 是 rareturn address register用于回到控制原点即回到函数调用的地方s0-s1(x8-x9)s2-s11(x18-x27)saved register保存寄存器 Numfunction callmeane.g.1jrjump register 跳转到寄存器jr ra1jaljump and link 跳转并链接jal rd, Label2jalrjump and link register 跳转并链接jalr rd, rs, imm jump and link表示跳转到某个地址并且函数调用的下一条指令的地址保存到ra 我们先来看一个函数执行的汇编代码示例 ... sum(a, b); ...int sum(int x, int y) {return x y; } - #address (decimal) 1000 mv a0, s0 # x a 1004 mv a1, s1 # y b 1008 addi ra, zero, 1016 # ra 1016 1012 j sum 1016 ... ... 2000 sum: add a0, a0, a1 2004 jr ra从上面的例子我们可以发现函数体在内存中的地址和主程序可能会离得比较远函数执行时有如下步骤 拷贝参数保存函数执行完成后的地址到ra跳转到函数并执行执行完成后跳转到ra 这里用到一条新的指令jr跳转到某个寄存器。为什么这边不用j来跳转呢因为j跳转需要很多标签如果函数返回要加标签那么可能到处都是这些标签了。 每次使用jr跳转时需要在函数执行前将控制点记录到ra中这可能会有些许麻烦RISC-V为我们提供了jal指令来帮助我们做保存返回地址的工作示例如下 1008 addi ra, zero, 1016 # ra 1016 1012 j sum - 1008 jal sum由于返回函数调用点非常常用所以用ret这个伪指令代替jr ra。 jal命令如果我们不需要返回地址则将他保存到x0jal x0, Label并且用伪指令j来替代。 6.2 关于函数调用的一些知识 6.1节中我们初步了解了函数调用接下来我们再通过一些示例来理解函数调用。我们先总结下CPU进行函数调用时需要经历的6个步骤 将参数放到函数可以获取到的地方寄存器将控制点交给函数jal获取函数需要的存储资源执行函数将函数返回值放到调用者可以获取的地方释放本地存储将控制点还给调用者ret。 这里有一个问题当CPU进行函数调用时寄存器会被用来存储函数中的变量原来寄存器中的值存应该如何存储呢函数调用结束时这些值应该如何恢复呢 存储这些值需要一块内存函数调用前将存储寄存器中旧的值存到内存中函数调用结束后从内存中恢复这些值并且删除掉他们。 这块内存被设计为栈结构stack: last in first out (LIFO)为了找到这块内存需要有一个寄存器指向这块地址这个寄存器x2被称为栈指针sp: stack pointer。 约定栈指针从高地址到低地址增长push动作减小栈指针的值pop增加栈指针的值。 接下来要了解栈帧stack frame的概念每一次函数调用所用到的内存块被称为栈帧栈帧里包含有返回指令的地址传入参数的值以及一些本地变量的值。 在嵌套函数调用中我们常称调用函数伪CalleR称被调用函数为CalleE。当被调用函数执行时调用函数需要知道哪些寄存器的值被改变了哪些寄存器的值没有被改变。为了减少从内存存储或者加载数据的次数寄存器被分成两类 在函数调用期间值可以保留的寄存器Caller只能依赖这些没有修改的寄存器例如sp、gp、tp函数调用期间值不能保留的寄存器例如参数寄存器a0-a7ra临时寄存器temporaryt0-t6。 以下是寄存器列表我们不需要非常了解每个寄存器的作用但是需要了解寄存器中的值由谁来保存 接下来看一个嵌套调用的例子 int sumSquare(int x, int y) {return mult(x, x) y; } - sumSquare:addi sp, sp, -8 # 先给stack开辟空间sw ra, 4(sp) # 存储 sumSquare rareturn addresssw a1, 0(sp) # 存储 y 到栈帧mv a1, a0 # 创建 mult 函数参数到寄存器 a0jal mult # 调用 mult 函数lw a1, 0(sp) # 保存 mult 返回值到栈帧add a0, a0, a1 # 完成加法计算lw ra, 4(sp) # 获取 raaddi sp, sp, 8 # 恢复栈指针jr ra # 返回 sumSquare 调用中 mult:...我们的程序在运行时变量会存在于三种内存空间中 static只会被声明一次的变量其生命周期一直到程序终止heap通过动态内存分配malloc声明的变量stack程序执行期间所用到的空间寄存器可以存储值到这块空间中 接下来了解下内存布局RV32 和 RV64、RV128的内存布局不一样这里了解RV32的内存布局 栈空间起始于高位地址并且向下增长栈空间必须进行16-bytes对齐test segment在内存的最底部静态数据段在文本段上面有一个global pointer(gp)指向静态区堆空间在静态区上面从低地址向高地址增长
http://www.zqtcl.cn/news/433973/

相关文章:

  • 威海网站开发询广西南宁网站运营
  • 网站的素材做logo长沙专业的网站建设企业
  • 网站显示速度的代码是什么情况专门做中式服装平台的网站
  • 驻马店做网站的公司大连网站模板建站
  • aso如何优化网站优化分析软件
  • IT周末做网站违反制度么wordpress 图床 插件
  • 成都网站建设scjsc888因网站建设关闭的公告
  • 唐山公司建设网站十大牌子网
  • 网站开发的选题依据电子商务网站建设内容
  • 中企动力做的网站被百度屏蔽推销网站话术
  • 四川网站制作广告设计自学网教程
  • 做个简单的企业小网站单纯做网站的公司
  • 河北省建设厅官方网站哈尔滨建设工程招聘信息网站
  • 茂名网站制作网页个人博客登录首页
  • 类似qq空间的网站wordpress 简历主题
  • 专业网站运营制作怎么写代码做网站
  • 安徽免费网站制作西安做行业平台网站的公司
  • 我想做服装网站怎么做网页设计优秀案例分析
  • 网站建设技术教程视频wordpress中文模版
  • 高端企业网站 程序纸牌网站建设
  • html制作网站推广最有效的办法
  • 做网站推广的工作内容凡客诚品创始人
  • 网站开发pc端和手机端外贸建设网站公司
  • 长沙哪家网站设计好上海成品网站
  • wordpress商城插件收费哪里可以做网站优化
  • 中国建设银行u盾下载假网站吗wordpress有没有付费
  • 海南哪家公司做网站开发一套管理系统多少钱
  • 做网站建设费用百姓网
  • 西安建设厅网站wpf做网站教程
  • 好的网页网站设计wordpress对外发邮件