汇编语言程序设计-2-访问寄存器和内存

2. 访问寄存器和内存

文章目录

  • 2. 访问寄存器和内存
    • 2.0 导学
    • 2.1 寄存器及数据存储
    • 2.2 mov和add指令
    • 2.3 确定物理地址的方法
    • 2.4 内存的分段表示法
    • 2.5 Debug的使用
    • 2.6 【代码段】CS、IP与代码段
    • 2.7 【代码段】jmp指令
    • 2.8 【数据段】内存中字的存储
    • 2.9 【数据段】用DS和[address]实现字的传送
    • 2.10 【数据段】DS与数据段
    • 2.11 【栈段】栈及栈操作的实现
    • 2.12 关于“段”的总结

  • 参考视频:烟台大学贺利坚老师的网课《汇编语言程序设计系列专题》,或者是B站《汇编语言程序设计 贺利坚主讲》,大家一起看比较热闹。
  • 中文教材:《汇编语言-第3版-王爽》(课程使用)、《汇编语言-第4版-王爽》(最新版)。
  • 老师的博客:《迂者-贺利坚的专栏-汇编语言》
  • 检测点答案参考:《汇编语言》- 读书笔记 - 各章检测点归档

本篇笔记对应课程第二章(下图倾斜),章节划分和教材对应关系如下。


2.0 导学

本章针对寄存器和内存的使用,开展如下学习内容:

【2.1 寄存器及数据存储】认识两者之间的关系。
【2.2 mov和add指令】通过这两个指令看到在运算中如何使用“寄存器”。
【2.3 确定物理地址的方法】CPU运行过程中,和内存的关系非常密切,所以介绍如何确定“物理地址”。
【2.4 内存的分段表示法】上面会分段使用内存,所以介绍“分段表示法”。
【2.5 Debug的使用】后续会非常频繁的使用Debug工具观察计算机内部状态。下面使用Debug工具观察内存的不同分段。

  • 代码段:【2.6 CS、IP与代码段】【2.7 jmp指令】
  • 数据段:【2.8 内存中字的存储】 【2.9 用DS和[address]实现字的传送】【2.10 DS与数据段】
  • 栈段: 【2.11 栈及栈操作的实现】

【2.12 关于“段”的总结】

2.1 寄存器及数据存储

图2-1 8086CPU的寄存器示意图

  在CPU中,“运算器”进行信息处理、“寄存器”进行信息存储、“控制器”协调各种器件进行工作、“内部总线”实现CPU内各个器件之间的联系。8086CPU所有的寄存器都是16位的,可以存放两个字节,8086CPU有14个寄存器(如上图标红):

  • 通用寄存器:AX(AH/AL)、BX(BH/BL)、CX(CH/CL)、DX(DH/D L)
  • 变址寄存器:SI、DI
  • 指针寄存器:SP、BP
  • 指令指针寄存器:IP
  • 段寄存器:CS、SS、DS、ES
  • 标志寄存器:PSW

而8086上一代CPU中的寄存器都是8位的,为了保证8086与上一代CPU程序兼容,“通用寄存器”均可以分为两个独立的8位寄存器使用。比如下图中,AX可以分为AH、AL:

图2-2 通用寄存器拆分——AX

  注意“字长(word size)”=“CPU的寄存器位宽”。因为8086是16位CPU,所以8086的字长为16bit。一个字(word)的高位字节(byte)存在这个寄存器的高8位寄存器、低位字节(byte)存在这个寄存器的低8位寄存器。但实际上,现代的CPU普遍是64位,此时“字长”就是64。

2.2 mov和add指令

图2-3 mov和add指令——默认十进制

  汇编指令不区分大小写。上图给出了movadd指令所完成的操作。现在假设 ax、bx 的初始值均为 0000H,那么下面两个程序分别展示了汇编指令程序的执行结果:

注意最后一步,左侧程序发生了溢出,最高位直接溢出。右侧程序add al,93H会直接舍弃低8位的进位,AX结果为 0058H;只有add ax,93H才会将低8位的进位保存到高8位中,AX结果为 0158H

【检测点2.1】

  1. 写出每条汇编指令执行后相关寄存器中的值。初始值为0000H。
汇编指令寄存器的值
mov ax,62627AX=F4A3H
mov ah,31H AX=31A3H
mov al,23H AX=3123H
add ax,ax AX=6246H
mov bx,826CHAX=6246H, BX=826CH
mov cx,ax AX=6246H, BX=826CH, CX=6246H
mov ax,bx AX=826CH, BX=826CH, CX=6246H
add ax,bx AX=04D8H, BX=826CH, CX=6246H
mov al,bh AX=0482H, BX=826CH, CX=6246H
mov ah,bl AX=6C82H, BX=826CH, CX=6246H
add ah,ah AX=D882H, BX=826CH, CX=6246H
add al,6 AX=D888H, BX=826CH, CX=6246H
add al,al AX=D810H, BX=826CH, CX=6246H
mov ax,cx AX=6246H, BX=826CH, CX=6246H
  1. 最多使用4条addmov指令,编程计算2的4次方。
mov ax,0002H # 2
add ax,ax    # 2+2=4
add ax,ax    # 4+4=8
add ax,ax    # 8+8=16

2.3 确定物理地址的方法

  CPU访问内存单元时要给出内存单元的地址。所有的内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,这个唯一的地址称为物理地址。但实际上,8086有20位地址总线,可传送20位地址,寻址能力为1M。但8086是16位结构的CPU,所以8086CPU使用两个16位地址(段地址、偏移地址)合成一个20位的物理地址:
物理地址 = 段地址 × 16 + 偏移地址 \bold{物理地址=段地址×16+偏移地址} 物理地址=段地址×16+偏移地址

  • 物理地址:20位。
  • 段地址:16位,相当于一个基础地址。“段地址×16”也就是“左移4位”。
  • 偏移地址:16位,也就是一个相对于基础地址的偏移地址。
图2-4 物理地址的生成方式、地址加法器的工作过程

注意,“段地址”并不是固定的,段地址和物理地址可以任意指定,只要最后的物理地址正确即可。

2.4 内存的分段表示法

  虽然8086使用分段的方式管理内存,但内存是一个完整空间并没有分段,段的划分来自于CPU!“段地址×16”被称为“段的起始地址”,显然“起始地址”一定是16的倍数;而“偏移地址”为16位,所以一个段的长度最大为 216=64K。同一段内存,多种分段方案,于是同一个物理地址也可以由不同的段地址和偏移地址组成,如下图所示:

图2-5 多种分段方案

段地址:用专门的寄存器存放段地址。下面是4个段寄存器:

  • CS - 代码段寄存器
  • DS - 数据段寄存器
  • SS - 栈段寄存器
  • ES - 附加段寄存器

偏移地址:可以用多种方法提供,也就是8086丰富的取址方式,也是汇编语言的重点。

最后补充一点,在8086PC机中,若数据存在内存的 2000H 段中的 1F60H 单元中,则存储单元地址表示为 2000:1F60。也就是 段地址:偏移地址的形式。

【检测点2.2】

  1. 给定段地址为0001H,仅通过变化偏移地址寻址,CPU 的寻址范围为 00010H 1000FH
  2. 有一数据存放在内存 20000H 单元中,现给定段地址为SA,若想用偏移地址寻到此单元。则 SA 应满足的条件是:最小为 1001H,最大为 2000H
    提示,反过来思考一下,当段地址给定为多少,CPU无论怎么变化偏移地址都无法寻到20000H单元?

2.5 Debug的使用

  Debug是DOS系统中的著名的调试程序,也可以运行在windows系统实模式下。使用Debug程序,可以查看CPU各种寄存器中的内容、内存的情况,并且在机器指令级跟踪程序的运行!Debug就是传奇!Debug一共有20多个命令,但下面这6个命令是和汇编学习密切相关的:

  • R命令:查看、改变CPU寄存器的内容
  • D命令:查看内存中的内容
  • E命令:改变内存中的内容
  • U命令:将内存中的机器指令翻译成汇编指令
  • A命令:以汇编指令的格式在内存中写入机器指令
  • T命令:执行机器指令
  • Q命令:退出debug

下面依次来进行演示:

启动Debug】在DOS提示符下输入命令:debug(也就是启动了masm文件夹中的Debug.exe)

用R命令查看、改变CPU寄存器的内容

  • R:查看寄存器内容
  • R 寄存器名:改变指定寄存器内容。可以没有中间的空格。
  • 左下角0000:0000:其实就是CS:IP,表示CPU当前要读取的指令所在的内存地址。
  • 左下角0000CS:IP内存地址中存放的机器码。
  • 下中间ADD [ES+SI],ALCS:IP内存地址中存放的指令的含义。
  • 右下角DS:0000=CD:刚才改变的寄存器值。后面还会介绍。

用D命令查看内存中的内容

  • D:列出从预设地址(CS:IP)开始,128个字节的内容。后续再调用 D会接着上一次的地址。右侧是ASCII码表示对应的字符。
  • D 段地址:偏移地址:列出指定地址开始,128个字节的内容。
  • D 段地址:偏移地址 结尾偏移地址:列出内存中指定地址范围内的内容,最多显示 216 个数据。

用E命令改变内存中的内容

  • E 段地址:偏移地址 数据1 数据2 ...:直接连续修改数据。
  • E 段地址:偏移地址:逐个询问式修改,空格表示继续修改;回车表示结束修改。
汇编指令对应的机器码
mov ax,0123HB8 23 01
mov bx,0003HBB 03 00
mov ax,bx89 D8
add ax,bx01 D8

用U命令将内存中的机器指令翻译成汇编指令

  • e 段地址:偏移地址 数据:写入指令对应的机器码。
  • d 段地址:偏移地址:查看写入的机器码。
  • u 段地址:偏移地址:将相应内存中的内容看作是“指令”,并进行翻译。

用A命令以汇编指令的格式在内存中写入机器指令

  • a 段地址:偏移地址:从指定地址处写入汇编指令。编写汇编程序时常用。
  • d 段地址:偏移地址:查看从指定地址开始的二进制机器码。
  • u 段地址:偏移地址:翻译从指定地址开始的二进制机器码,会根据汇编指令的不同自动切割字节。

用T命令执行机器指令

  • t:从 CS:IP处,逐条执行机器指令。

用Q命令退出Debug

  • q:退出Debug

2.6 【代码段】CS、IP与代码段

  CS为代码段寄存器,IP 为指令指针寄存器,它们是8086CPU中两个最关键的寄存器。从名称上我们可以看出它们和指令的关系。CS:IP指示了CPU当前要读取指令的地址。8086CPU读取指令时,会通过“地址加法器”将要读取的指令地址传输到数据总线,内存会一次性发送完整的一条指令给CPU执行(指令的操作码包含指令长度信息),此时 IP 自动增加当前指令长度,然后继续读取下一指令并执行。如下图:

图2-6 8086CPU读取和执行指令的相关部件

【8086CPU 当前状态】
CS:IP2000H:0000H,内存 20000H~20009H 单元存放着可执行的如下机器码:

  • 地址 20000H~20002H,长度 3Byte,内容 B8 23 01,对应汇编指令 mov ax,0123H
  • 地址 20003H~20005H,长度 3Byte,内容 BB 03 00,对应汇编指令 mov bx,0003H
  • 地址 20006H~20007H,长度 2Byte,内容 89 D8,对应汇编指令 mov ax,bx
  • 地址 20008H~20009H,长度 2Byte,内容 01 D8,对应汇编指令 add ax,bx

笔者注:CS:IP就相当于“计算机组成原理”中的PC(计数器)。

注意到,机器码存储在内存中,既可以是数据、也可以是内存。但是CPU会将 CS:IP指向的内存单元中的内容默认看作指令!

【实证演示】

  1. 写入汇编指令。
  2. 查看汇编指令。
  3. 执行代码。

2.7 【代码段】jmp指令

  在实际的程序运行过程中,经常会出现程序的跳转,比如程序进入中断时需要跳转到“中断向量入口地址”。上一小节又讲到 CS:IP就是当前指令地址,于是要实现程序跳转本质上就需要修改 CS:IP,有如下方法:

  1. debug的R命令:上一小节用到的方法,但debug只是一个调试工具,而非汇编程序本身!
  2. mov指令:mov CS,2000mov IP,0000,但是8086CPU不支持使用mov指令修改CS和IP。
  3. jmp指令:转移指令,专门用于程序跳转!
  • jmp 段地址:偏移地址:将CS修改为“段地址”,IP修改为“偏移地址”。
  • jmp 寄存器名:只是将IP修改为寄存器中的值,比如 jmp ax相当于 mov IP,ax(实际并不能这样使用mov)。

下面通过一个演示,来验证 jmp指令的作用:

【实证演示】
假设在下图所示的内存中存放相应的指令,并且程序从 2000H 执行,那么执行序列最后会进入死循环。

  此时,我们可以规定某个“段地址”就对应一个“代码段”,这个“代码段”的最大长度为 216=64K 个字节。但注意CPU本身并不会有这样的区分,只是这样规定可以使得代码的存放位置更加清晰。

【检测点2.3】
下面的3条指令执行后,CPU几次修改IP?都是在什么时候?最后IP中的值是多少?

mov ax, bx
sub ax, ax
jmp ax

答:IP 总共改了4次:读取每条指令后IP修改一次;执行 jmp ax再修改一次。最后 IP 中的值是 0 (因为 sub ax,ax后 ax=0000H)。

2.8 【数据段】内存中字的存储

  8086CPU中,一个“”为16位,于是需要两个连续的字节单元存放,被称为“字单元”。高8位放高字节,低8位放低字节,也就是计组中的“小端模式”。于是,一个“单元”存放一个“字节型数据”、一个“字单元”存放一个“字型数据”。下图中,前两种都是小端模式,但是将高地址写在上面方便阅读(中间图):

图2-7 内存中字的存储-小端模式

2.9 【数据段】用DS和[address]实现字的传送

  8086CPU中的内存单元地址都是 段地址:偏移地址的格式,CPU寄存器 CS:IP表示当前的指令地址,于是 DS:[...] 则表示想读取的数据(字单元)的地址。另外,8086CPU不支持将数据直接送入段寄存器(硬件设计的问题),所以段地址写入顺序固定为:数据 -> 一般的寄存器 -> 段寄存器。如下:

  • DS寄存器:存放要访问的数据的段地址。
  • [...]:直接给出16位的偏移地址(16进制),而不是特定的寄存器。

【示例1】将10000H(1000:0)中的数据读到al中

mov bx,1000H
mov ds,bx
mov al,[0]

【示例2】将al中的数据写到10000H(1000:0)中

mov bx,1000H
mov ds,bx
mov [0],al

【实证演示1】按照下图调整数据和内存,注意不同偏移地址的 读出数据

【实证演示2】注意观察写入数据时,也是小端模式。

2.10 【数据段】DS与数据段

  和“代码段”类似,根据数据的内存单元地址为 DS:[偏移地址],我们也可以利用 数据段寄存器DS 将一组内存单元定义为一个“数据段”,而具体的数据单元则由 [偏移地址]给出。同样,“数据段”也是编程时的人为安排,与8086CPU或者内存的物理结构无关。下面是一个利用“数据段”进行编程的示例:

【程序1】累加数据段中的前3个单元中的数据:使用寄存器 ax 的低8位 al。

mov ax, 123BH
mov ds, ax
mov al, 0
add al, [0]
add al, [1]
add al, [2]

【程序2】累加数据段中的前3个字型数据:使用完整的16位寄存器 ax。

mov ax, 123BH
mov ds, ax
mov ax, 0
add ax, [0]
add ax, [2]
add ax, [4]

下面针对 movaddsub这三个指令,给出其支持的指令格式。其他没有提到的指令格式,可以在debug中尝试。

表2-1 mov、add、sub 的指令格式
类型mov指令形式例示add指令形式例示sub指令形式例示
寄存器mov 寄存器,数据mov ax, 8add 寄存器,数据add ax, 8sub 寄存器,数据sub ax, 8
mov 寄存器,寄存器mov ax, bxadd 寄存器,寄存器add ax, bxsub 寄存器,寄存器sub ax, bx
mov 寄存器,内存单元mov ax, [0]add 寄存器,内存单元add ax, [0]sub 寄存器,内存单元sub ax, [0]
mov 寄存器,段寄存器mov ax, dsadd 寄存器,段寄存器不支持sub 寄存器,段寄存器不支持
内存单元mov 内存单元,数据不支持add 内存单元,数据不支持sub 内存单元,数据不支持
mov 内存单元,寄存器mov [0], axadd 内存单元,寄存器add [0], axsub 内存单元,寄存器sub [0], ax
mov 内存单元,内存单元不支持add 内存单元,内存单元不支持sub 内存单元,内存单元不支持
mov 内存单元,段寄存器mov [0], dsadd 内存单元,段寄存器不支持sub 内存单元,段寄存器不支持
段寄存器mov 段寄存器,数据不支持add 段寄存器,数据不支持sub 段寄存器,数据不支持
mov 段寄存器,寄存器mov ds, axadd 段寄存器,寄存器不支持sub 段寄存器,寄存器不支持
mov 段寄存器,内存单元mov ds, [0]add 段寄存器,内存单元不支持sub 段寄存器,内存单元不支持
mov 段寄存器,段寄存器不支持add 段寄存器,段寄存器不支持sub 段寄存器,段寄存器不支持

【数据段-小结】

  1. 字在内存中存储时,要用两个地址连续的内存单元来存放,字的低位字节存放在低地址单元中,高位字节存放再高地址单元中。
  2. mov指令要访问内存单元,可以在 mov指令中只给出单元的偏移地址,此时,段地址默认在DS寄存器中。
  3. [address]表示一个偏移地址为address的内存单元。
  4. 在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器、低地址单元和低8位寄存器相对应。
  5. movaddsub是具有两个操作对象的指令,访问内存中的数据段。jmp是具有一个操作对象的指令,对应内存中的代码段。
  6. 可以根据自己的推测,在Debug中实验指令的新格式。

2.11 【栈段】栈及栈操作的实现

  “”是一种只能在一端进行插入或删除操作的数据结构,符合LIFO(Last In First Out,后进先出)的操作规则。现今的CPU中都有栈的设计,也就是8086CPU提供相关的栈指令,支持用栈的方式访问内存空间,并且寄存器 SS:SP始终指向栈顶元素的地址。下面是 SS:SP以及 栈操作指令:

  • 栈段寄存器SS:存放栈顶的段地址,同时也默认为最小的栈顶地址。
  • 栈顶指针寄存器SP:存放栈顶的偏移地址,初始值为栈的大小(可以理解为栈底)。
  • push ax:将ax中的数据送入栈中,SP自动减2(以字为单位)。
  • pop ax:从栈顶取出数据送入ax,SP自动加2(以字为单位)。

【实例演示】使用pushpop交换ax和bx中的内容。

  • 初始栈顶始终不存储任何有效元素。
  • 第一个元素存储在初始栈顶指针SP的上一个字。

  若不断的调用 push或者pop指令,就会导致 SP 指针超出栈的范围,也就是“栈顶超界问题”。遗憾的是,8086CPU只知道栈顶在何处(SS:SP),却不知道程序安排的栈空间有多大,8086CPU不保证对栈的操作不会超界。为了防止超界,汇编语言程序员需要格外小心。

2.12 关于“段”的总结

  由于内存地址为 段地址:偏移地址,所以每一种“段”的起始地址都是16的倍数。目前我们学习了三种段:

  1. 数据段:将段地址放在 DS 中。用mov、add、sub等访问内存单元的指令时,CPU将我们定义的数据段中的内容当作数据段来访问。
  2. 代码段:将段地址放在 CS 中,将段中第一条指令的偏移地址放在 IP 中。CPU将执行我们定义的代码段中的指令。
  3. 栈段:将段地址放在 SS 中,将栈顶单元的偏移地址放在 SP 中。CPU在需要进行栈操作(push、pop)时,就将我们定义的栈段当作栈空间来用。

实际在编写汇编语言程序时,为了逻辑清晰,可以对不同的段进行分区,可以将三个段全部分开或者放在一起。但注意“段”的划分只取决于汇编语言程序员,与CPU设计无关。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/11939.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【自动驾驶技术栈学习】1-硬件《大话自动驾驶》| 综述要点总结 by.Akaxi

----------------------------------------------------------------------------------------------------------------- 致谢:感谢十一号线人老师的《大话自动驾驶》书籍,收获颇丰 链接:大话自动驾驶 (豆瓣) (douban.com) -------------…

618购物狂欢不知道怎么买?请收下这份好物清单,直接闭眼入!

在繁忙的618购物狂欢节来临之际,面对琳琅满目的商品,你是否感到无从下手?别担心,我们精心整理了一份好物清单,汇聚了各类热销与口碑兼具的精品。无论你是追求品质生活的消费者,还是寻找实惠好物的网购达人&…

实时网络监控 - 一目了然网络状况

网络问题排查一直是IT管理员头痛的问题。随着网络规模的不断扩大和业务复杂度的提升,如何快速定位和解决网络故障变得尤为关键。本文详细介绍了一款名为 AnaTraf 的网络流量分析工具,它能提供全流量回溯分析、实时网络监控、性能分析等功能,助力企业快速诊断和解决各…

AI绘画Stable Diffusion换脸插件ReActor 不香了,新一代换脸神器 InstantID!

前 言 之前我介绍了 SD 中的一款换脸插件 ReActor,虽然好使,但是安装还是有些许麻烦的。 今天给小伙伴们介绍一款新型的换脸插件:InstantID,主要是使用 ControlNet 和 IP-Adapter 的组合来控制扩散过程中的面部特征。 一句话&a…

Hive的join操作

假设有三张表,结构和数据如下:-- 创建表 test_a,test_b,test_c CREATE TABLE test_a( id int, name string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY \t;--分别导入数据到三个表中 --test_a 1 a1 2 a2 4 a4 --test_b 1 b1 3 b3 4 b4 --…

【Vue探索之旅】初识Vue

文章目录 前言 渐进式框架​ 入门案例 完结撒花 前言 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手&#x…

XWiki 服务没有正确部署在tomcat中,如何尝试手动重新部署?

1. 停止 Tomcat 服务 首先,您需要停止正在运行的 Tomcat 服务器,以确保在操作文件时不会发生冲突或数据损坏: sudo systemctl stop tomcat2. 清空 webapps 下的 xwiki 目录和 work 目录中相关的缓存 删除 webapps 下的 xwiki 目录和 work …

angular13 自定义组件全项目都可用 自存

1.定义自定义组件 使用命令创建一个组件 但删除它在你的module里的声明,因为会报错只能引用一次 在本组件中创建一个module文件,引入刚才的组件component.ts import { NgModule } from angular/core; import { CommonModule } from angular/common; im…

[ES] ElasticSearch节点加入集群失败经历分析主节点选举、ES网络配置 [publish_address不是当前机器ip]

背景 三台CentOS 7.6.1虚拟机, 每台虚拟机上启动一个ElasticSearch 7.17.3(下面简称ES)实例 即每台虚拟机上一个ES进程(每台虚拟机上一个ES节点) 情况是: 之前集群是搭建成功的, 但是今天有一个节点一…

函数编辑器调研及设计开发

前言:在产品研发中需要一款可嵌入web开发的代码及函数编辑器,本文从功能,扩展,外观/交互,维护/社区,兼容性,开源与否等方面考虑,进行对比筛选 1、编辑器统计数据 市面上编辑器有很…

Windows电脑使用Docker安装AList网盘神器并配置公网地址打造私人云存储空间

文章目录 前言1. 使用Docker本地部署Alist1.1 本地部署 Alist1.2 访问并设置Alist1.3 在管理界面添加存储 2. 安装cpolar内网穿透3. 固定Alist公网地址 前言 本文和大家分享如何在Windows系统使用Docker本地部署Alist全平台网盘神器,然后结合cpolar内网穿透工具实现…

USE INDEX/FORCE INDEX/IGNORE INDEX使用的好,sql查询速度提升一倍

前言 在实际工作中有些时候数据库的执行就很奇怪,要么不用索引,要么用了错误的索引,那么在这种情况下你就可以考虑使用这些索引提示来纠正数据库的行为。 早期我们有一个表结构定义,上面有 A、B 两个索引。原本按照预期&#x…

SCQA表达模型:让你的表达更具吸引力(2)

一、引言 站在巨人的肩膀上,思维模型是前人智慧结晶,当我们面对相似挑战时,借鉴与模仿这些模型,往往能为我们带来意想不到的结果。 在信息爆炸的时代,如何高效、准确地传达信息成为了人们关注的焦点。SCQA表达模型作为…

网络网络层之(5)IPv6协议

网络网络层之(5)IPv6协议 Author: Once Day Date: 2024年5月12日 一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦… 漫漫长路,有人对你微笑过嘛… 全系列文档可参考专栏:通信网络技术_Once-Day…

「JavaEE」多线程案例分析2:实现定时器

🎇个人主页:Ice_Sugar_7 🎇所属专栏:JavaEE 🎇欢迎点赞收藏加关注哦! 实现定时器 🍉简介🍉模拟实现定时器 🍉简介 定时器类似一个闹钟,时间到了之后就会执行…

重生我是嵌入式大能之串口调试UART

什么是串口 串口是一种在数据通讯中广泛使用的通讯接口,通常我们叫做UART (通用异步收发传输器Universal Asynchronous Receiver/Transmitter),其具有数据传输速度稳定、可靠性高、适用范围广等优点。在嵌入式系统中,串口常用于与外部设备进…

MTATLAB--一元线性回归分析

一文让你彻底搞懂最小二乘法(超详细推导) 在进行一元线性回归分析时,使用最小二乘法进行解题,关于最小二乘法具体看上述文章。 数据文件在文章顶部可见,将第一列数据作为自变量x,第二列数据作为应变量y。建…

3款常用的可视化工具Matplotlib、Seaborn和Pandas

大家好,Seaborn 是基于 Matplotlib 的扩展库,Pandas 的可视化功能同样也依赖于 Matplotlib。尽管二者都使用相同的底层图形库,但绘制图表的方法却各有千秋。本文将介绍各种柱状图的绘制,比较 Matplotlib、Pandas 和 Seaborn 在数据…

vulhub靶机struts2环境下的s2-032(CVE-2016-3081)(远程命令执行漏洞)

影响范围 Struts 2.3.19至2.3.20.2、2.3.21至2.3.24.1和2.3.25至2.3.28 当用户提交表单数据并验证失败时,后端会将用户之前提交的参数值使用OGNL表达式%{value}进行解析,然后重新填充到对应的表单数据中。 漏洞搭建 没有特殊要求,请看 (3…

EasyImage2.0 图床源码

EasyImage2.0 是一个简单图床的源码,它支持以下功能: 1. API接口 2. 登录后才能上传图片 3. 设置图片质量 4. 压缩图片大小 5. 添加文字或图片水印 6. 设定图片的宽度和高度 7. 将上传的图片转换为指定的格式 8. 限制上传图片的最小宽度和高度 …