5. ARM_指令集
概述
分类
汇编中的符号:
- 指令:能够编译生成一条32位机器码,并且能被处理器识别和执行
- 伪指令:本身不是指令,编译器可以将其替换成若干条指令
- 伪操作:不会生成指令,只是在编译阶段告诉编译器怎么编译
对于不同的CPU,指令和伪指令不同。因为指令和伪指令都由CPU来直接识别。
对于不同的编译器,伪操作不同,因为伪操作是控制编译器编译的。
ARM指令集的分类:
- 数据处理指令:进行数学运算、逻辑运算
- 跳转指令:实现程序的跳转,本质就是修改了PC寄存器
- Load/Store指令:访问(读写)内存
- 状态寄存器传送指令:用于访问(读写)CPSR寄存器
- 软中断指令:触发软中断
- 协处理器指令:操作协处理器的指令
其中数据处理指令、跳转指令、Load/Store指令是通用指令,任何一个CPU都具有该指令。并且这些指令在C语言中都有对应的语句。
指令格式:
汇编语言不区分大小写,但是不要出现一个指令里面既有大写也有小写。比如:可以写MOV或mov,但不要写成Mov
立即数
什么是立即数:
立即数就是能够写在指令后面的数,例如 " MOV R0 #1 " 这个#1当中的数就是立即数。
立即数的本质就是包含在指令当中的数,属于指令的一部分。
注意:立即数不能写到32位,因为汇编指令转为机器码后是32位,这32位中有几位用来表示指令含义和寄存器含义,因此数据位并没有32位。
立即数与变量的区别:
立即数是指令的一部分,在使用立即数赋值时,CPU直接从机器码中就可以获取数据,不需要从内存中读取相应的值。
变量是存放在内存中,通过变量赋值,CPU必须先从内存中取出,再进行赋值。
32位非立即数却可赋值的情况:
当我们使用MOV R0, #0xFFFFFFFF这个指令时,0xFFFFFFFF是一个32位的数,一定不是一个立即数,但最终编译未出错。具体的编译器处理结果如下:
在这里,编译器将MOV R0, #0xFFFFFFFF 替换成了 MVN R0,#00000000,这个MVN的指令就是CPU可以识别执行的指令,原先的MOV就被称作伪指令。
条件码
条件码就是一个条件,当条件满足时执行这个操作,条件不满足时不执行该操作。
大多数的指令后都可以添加条件,具体示例见"跳转指令" - "2、B"
在使用条件码时,需要先使用CMP进行比较,之后再使用条件码进行条件执行。
条件码如下:
数据处理指令
1、数据搬移指令
1.1 MOV
将指定的数据搬移(赋值)到指定的寄存器中。
格式:
MOV 目标寄存器, 源操作数
目标寄存器: 可以为通用寄存器R0~R12,也可以是PC
源操作数:可以是立即数,也可以是寄存器
示例:
将立即数3搬移到寄存器R1,即:令R1=3
MOV R1, #3 @ #3代表十进制的3,#0x3代表十六进制的3
将R2寄存器的值搬移到寄存器R1,即:令R1=R2
MOV R1, R2
1.2 MVN
将指定的数据按位取反后,搬移(赋值)到指定的寄存器中。
格式:
MVN 目标寄存器, 源操作数
示例:
将立即数0xFF取反后的值搬移到寄存器R1,即:令R1 = ~0xFF。
注意:这时R1存放的值为0xFFFFFF00,而不是0,因为ARM的寄存器是32位,所以在ARM寄存器中0xFF的存放值是0x000000FF,因此按位取反后为0xFFFFFF00,而不是0。
MVN R1 #0xFF
2、数值运算指令
一般格式:<操作码> <目标寄存器> <第一操作寄存器> <第二操作数>
- 操作码:执行什么操作,如加减乘除
- 目标寄存器:用于存放运算结果
- 第一操作寄存器:必须是一个寄存器,是参与运算的数。
- 第二操作数:可以是寄存器,也可以是立即数,这也是参与运算的数。
2.1 ADD
加法指令,将指定的两个数进行相加,结果存入指定的寄存器。
格式:
ADD 目标寄存器, 源寄存器, 源操作数
目标寄存器: 可以为通用寄存器R0~R12,也可以是PC
源寄存器:只能是寄存器
源操作数:可以是立即数,也可以是寄存器
示例:
已知R2=5,R3=3,实现R1=R2+R3
MOV R2,#5
MOV R3,#3
ADD R1,R2,R3 @ R1 = R2 + R3
已知R2=5,实现R1=R2+5
MOV R2,#5
ADD R1,R2,#5 @ R1 = R2 + 5
注意:这里不能写成ADD R1,#5,R2 对应ADD只有最后一个为源操作数
2.2 ADC
带进位的加法指令,将指定的两个数进行相加,并且会加上CPSR的进位。
ADC实现64位运算:
实现:
0x00000001 00000002 + 0x00000003 00000004
思路:
将第一个数的低位和高位分别存放在R1、R2;将第二个数的低位和高位分别存放在R3、R4;将结果的低位和高位分别存放在R5、R6
运算代码:
MOV R1,0x00000002
MOV R2,0x00000001
MOV R3,0x00000004
MOV R4,0x00000003ADDS R5,R1,R3 @将两个低位相加并允许设置CPSR
ADC R6,R2,R4 @将两个高位相加并加上CPSR的C位(溢出进位)
ADCS实现128位运算:
实现:
0x00000001 00000002 00000003 00000004 + 0x00000005 00000006 00000007 00000008
运算代码:
MOV R1,0x00000004
MOV R2,0x00000003
MOV R3,0x00000002
MOV R4,0x00000001MOV R5,0x00000008
MOV R6,0x00000007
MOV R7,0x00000006
MOV R8,0x00000005ADDS R9,R1,R5 @将两个低位相加并允许设置CPSR
ADCS R10,R2,R6 @将两个高位相加并加上CPSR的C位(溢出进位)并允许设置CPSR
ADCS R11,R3,R7 @将两个高位相加并加上CPSR的C位(溢出进位)并允许设置CPSR
ADC R12,R4,R8 @将两个高位相加并加上CPSR的C位(溢出进位)
2.3 SUB
减法指令,将指定的两个数进行相减,结果存入指定的寄存器。
该指令只能实现 "寄存器 - 寄存器" 或者 "寄存器 - 立即数" 但实现不了 "立即数 - 寄存器"
格式:
SUB 目标寄存器, 源寄存器, 源操作数
目标寄存器: 可以为通用寄存器R0~R12,也可以是PC
源寄存器:只能是寄存器
源操作数:可以是立即数,也可以是寄存器
注意:SUB减法中有顺序,源寄存器存放的是被减数,源操作数存放的是减数。
示例:
已知R2=5,R3=3,实现R1=R2-R3
MOV R2,#5
MOV R3,#3
SUB R1,R2,R3 @ R1 = R2 - R3
已知R2=5,实现R1=R2-5
MOV R2,#5
SUB R1,R2,#5 @ R1 = R2 - 5
注意:这里不能写成SUB R1,#5,R2 对应SUB只有最后一个为源操作数
2.4 SBC
带借位的减法指令,将指定的两个数进行相减,并且会减去CPSR的借位(C位取反)。
SBC实现64位运算:
实现:
0x00000002 00000001 - 0x00000001 00000002
运算代码:
MOV R1,0x00000001
MOV R2,0x00000002
MOV R3,0x00000002
MOV R4,0x00000001SUBS R5,R1,R4 @将两个低位相减并允许设置CPSR
SBC R6,R2,R5 @将两个高位相减并减去CPSR的C位取反(借位)
2.5 RSB
逆向减法指令,将指定的两个数进行相减,结果存入指定的寄存器。
该指令通过被减数与减数调换,解决了SUB不能实现"立即数 - 寄存器"的问题。
格式:
RSB 目标寄存器, 源寄存器, 源操作数
目标寄存器: 可以为通用寄存器R0~R12,也可以是PC
源寄存器:只能是寄存器
源操作数:可以是立即数,也可以是寄存器
注意:RSB减法中有顺序,源寄存器存放的是减数,源操作数存放的是被减数。这与SUB相反。
示例:
实现R1 = 3 - R2。
RSB R1,R2,#3 @ R1 = 3 - R2
2.6 MUL
乘法指令,将指定的两个数进行相乘,结果存入指定的寄存器。
格式:
MUL 目标寄存器, 源寄存器, 源寄存器
目标寄存器: 可以为通用寄存器R0~R12,也可以是PC
源寄存器:只能是寄存器
注意:乘法指令中只能是两个寄存器相乘,不能使用立即数。
示例:
实现R1 = R2 * R3。
MUL R1,R2,R3 @ R1 = R2 * R3
3、位运算指令
3.1 AND
按位与指令,将指定的两个数进行按位与,结果存入指定的寄存器。
格式:
AND 目标寄存器, 源寄存器, 源操作数
目标寄存器: 可以为通用寄存器R0~R12,也可以是PC
源寄存器:只能是寄存器
源操作数:可以是立即数,也可以是寄存器
示例:
实现R1 = R2 & R3。
AND R1,R2,R3 @R1 = R2 & R3
3.2 ORR
按位或指令,将指定的两个数进行按位或,结果存入指定的寄存器。
格式:
ORR 目标寄存器, 源寄存器, 源操作数
目标寄存器: 可以为通用寄存器R0~R12,也可以是PC
源寄存器:只能是寄存器
源操作数:可以是立即数,也可以是寄存器
示例:
实现R1 = R2 | R3。
ORR R1,R2,R3 @R1 = R2 | R3
3.3 EOR
按位异或指令,将指定的两个数进行按位异或,结果存入指定的寄存器。
格式:
EOR 目标寄存器, 源寄存器, 源操作数
目标寄存器: 可以为通用寄存器R0~R12,也可以是PC
源寄存器:只能是寄存器
源操作数:可以是立即数,也可以是寄存器
示例:
实现R1 = R2 ^ R3。
EOR R1,R2,R3 @R1 = R2 ^ R3
3.4 LSL
左移指令,将指定的数左移指定的位,结果存入指定的寄存器。
格式:
LSL 目标寄存器, 源寄存器, 源操作数
目标寄存器: 可以为通用寄存器R0~R12,也可以是PC
源寄存器:只能是寄存器
源操作数:可以是立即数,也可以是寄存器
示例:
实现R1 = R2 << 3
方式1:寄存器法
MOV R3,#3
LSL R1,R2,R3 @R1 = R2 << 3方式2:立即数法
LSL R1,R2,#3 @R1 = R2 << 3
3.4 LSR
右移指令,将指定的数右移指定的位,结果存入指定的寄存器。
格式:
LSR 目标寄存器, 源寄存器, 源操作数
目标寄存器: 可以为通用寄存器R0~R12,也可以是PC
源寄存器:只能是寄存器
源操作数:可以是立即数,也可以是寄存器
示例:
实现R1 = R2 >> 3
方式1:寄存器法
MOV R3,#3
LSR R1,R2,R3 @R1 = R2 >> 3方式2:立即数法
LSR R1,R2,#3 @R1 = R2 >> 3
3.5 BIC
位清零指令,将指定的位进行清零,结果存入指定的寄存器。
格式:
BIC 目标寄存器, 源寄存器, 源操作数
目标寄存器: 可以为通用寄存器R0~R12,也可以是PC
源寄存器:只能是寄存器
源操作数:可以是立即数,也可以是寄存器
注意:清零源操作数为1的位数,为0的位数不进行操作。但源寄存器的数值不进行改变
示例:
已知R2=0xFF,实现将R2低四位清零,并把结果写入到R1中,并且R2值不进行改变。
MOV R2,#0xFF
BIC R1,R2,#0x0F @0x0F的低四位为1,所以R2的低4位被清零,结果存入到R1@运算之后R1=0xF0,R2=0xFF(值不改变)
4、其他
4.1 格式扩展
格式扩展示例:
MOV R3, R0, LSL #3 ; 将R0的值左移3位后存入R3
格式扩展指令的看法:
首先这里面有MOV、LSR这两个指令,最前面的MOV是操作码,所以这个整体指令的功能是数据搬移功能,因此R0为第一操作数,LSL #3为第二操作数。
这里的LSL #3并不是一个指令,含义是左移3,操作的数据源就是前面的R0,返回的结果存放在前面的R3。因此最终功能是将R0的值左移3位后存入R3。
4.2 运算影响CPSR
指令后加S影响CPSR:
默认情况下,数据运算不会对CPSR的条件位产生影响。当指令加上后缀 "S" 后,即可影响CPSR
MOV R1,#3
SUB R2,R1,#5 @这计算是一个负数,但没有加S后缀,所以CPSR的N位不置1MOV R1,#3
SUBS R2,R1,#5 @这计算是一个负数,加了S后缀,所以CPSR的N位置1
跳转指令
1、CMP指令
比较指令,比较两个寄存器值中的关系,比较的结果存储再CPSR的NZCV中。
CMP的本质就是一条减法指令(SUBS),只是没有将运算结果存入寄存器。
格式:
CMP 源寄存器1 源寄存器2
当源寄存器1 == 源寄存器2时,CPSR中的 Z = 1。
当源寄存器1 != 源寄存器2时,CPSR中的 Z = 0。
当源寄存器1 < 源寄存器2时,CPSR中的 C = 0。
当源寄存器1 <= 源寄存器2时,CPSR中的 C = 0 或者 Z = 1。
当源寄存器1 > 源寄存器2时,CPSR中的 C = 1 且 Z = 0(相等时也不产生借位)。
当源寄存器1 >= 源寄存器2时,CPSR中的 C = 1。
示例:
实现1~100求和,结果存入R2。
2、B
跳转到指定的位置。跳转指令的本质就是修改PC指向。
注意:默认情况下LR不会自动保存下一条指令的地址,加上后缀 "L" 可以允许LR保存下一条指令的地址。
B称为不带返回的跳转指令,BL称为带返回的跳转指令。
格式:
B 条件码 标签
条件码可以不写,当不写时为无条件跳转,当写时为有条件跳转。 条件码如下:
示例:
1、无返回跳转到FUNC标号下的第一条指令位置。
当执行 " B FUNC " 之后,PC将指向 "MOV R6,#6" 并在下一次执行该指令。
2、有返回跳转到FUNC标号下的第一条指令位置,执行之后再返回。
当执行 " BL FUNC " 之后,PC将指向 "MOV R6,#6" 并且 LR存储了 "MOV R4,#4"的位置。
当执行 " MOV PC,LR "之后,PC将指向 "MOV R4,#4" 实现了返回。
3、条件跳转,当R1=R2时,跳转到FUNC
当指向 "BEQ FUNC" 后,因为R1==R2不成立,所以不跳转,继续执行 "MOV R3,#3" 指令
4、跳转到自身
指令 "B ." 代表跳转到自身。
比如 "B ." 存在0x00000004处,执行完该指令后PC依旧指向0x00000004
Load/Store指令
1、单寄存器内存访问
1.1 STR
将指定寄存器中的数据存储到指定的内存地址中。
指令与存放数据的字节数:
- STR -- 4字节
- STRH -- 2字节
- STRB -- 1字节
格式:
STR 源寄存器 [目标寄存器]
目标寄存器中存放内存的地址
注意:源寄存器中数据为多少字节,那么目标寄存器存放的地址就得为多少的整数倍。
示例:
将R1的数据写入到R2存放的地址的位置。
这里R2存放的0x40000000为内存,这是因为地址映射时规定了这个地址是内存的起始地址。
这里R1的数据为0xFF000000是4字节,因此R2存放的地址应该为4的整数倍,所以如果R2的值为0x40000001,这就是错误的地址。
1.2 LDR
将指定的内存地址中的数据读取到指定寄存器中。
指令与取出数据的字节数:
- LDR -- 4字节
- LDRH -- 2字节
- LDRB -- 1字节
格式:
LDR 目标寄存器 [源寄存器]
源寄存器存放的是所需取数据的数据地址。
示例:
将R2中存放的地址的数据读出来,存放到R3当中。
该代码运行结束后,R3就存放了0xFF000000
2、多寄存器内存访问
2.1 STM
将多个寄存器中的数据存储到指定的内存地址中。
格式:
STM 目标地址 {源寄存器}
源寄存器:当寄存器连续时,使用 "-"链接;当寄存器不连续时,使用 ","分隔。
如 "STM R11,{R1-R4}" 这操作的时R1、R2、R3、R4
如 "STM R11,{R1,R4}" 这操作的时R1、R4
示例:
将R1~R4寄存器的值存放到以某个地址为起点的地址空间
这里的R11没有加 "[ ]",但它的数据含义代表地址
列表顺序并不是真正的存储顺序, 存储顺序一定是小编号的寄存器存低地址数据。
如上述STM指令写成 "STM R11,{R1,R4,R2,R3}",存储顺序依旧是和 "STM R11,{R1-R4}"一致,而不是0x40000020存放R1,0x40000024存放R4....
2.2 LDM
将指定的内存地址中的数据读取到多个寄存器中。
格式:
LDM 读取起始地址 {目标寄存器}
目标寄存器:当寄存器连续时,使用 "-"链接;当寄存器不连续时,使用 ","分隔。
如 "LDM R11,{R6-R9}" 这操作的时R6、R7、R8、R9
如 "LDM R11,{R6,R9}" 这操作的时R6、R9
示例:
将某个地址为起点的地址空间的数据读取到R6~R9寄存器中
这里的R11没有加 "[ ]",但它的数据含义代表地址
列表顺序并不是真正的存储顺序, 存储顺序一定是小编号的寄存器存低地址数据。
如上述LDR指令写成 "LDR R11,{R6,R9,R7,R8}",存储顺序依旧是和 "LDR R11,{R6-R9}"一致。
状态寄存器传送指令
该指令常用于操作系统内部,比如刚上电时,初始化系统时使用该指令。
1、MRS
将CPSR的值读取到指定寄存器
格式:
MRS 目标寄存器 CPSR
示例:
2、MSR
将指定数据写入到CPSR中
注意:特权模式下可以只写改变CPSR的值,User模式下不能直接改变CPSR的值。
格式:
MSR CPSR 源操作数
示例:
软中断指令
1、SWI
该指令常用于操作系统内部,比如在User模式下调用系统调用时,Linux就会写一个SWI的指令将User模式转换成SVC模式,从而有足够的权限处理硬件。这个过程其实就是使用SWI指令将用户态切换到内核态。
格式:
SWI #参数
参数:这个值用于区分不同的硬件。用户态切换到内核态都是调用SWI来实现,但究竟调用哪一个硬件CPU并不清楚,此时CPU就需要该参数来得知调用哪一个硬件。
2、模拟实现软中断处理过程
流程描述:
- 当程序复位,PC指向0x00处,0x00处存放了异常向量表Reset,跳转到MAIN函数。
- 执行MAIN函数到SWI语句,产生了软中断异常。软中断异常是由SVC模式进行处理,所以CPU自动拷贝CPSR到SPSR_svc中,并且修改CPSR、保存返回地址到LR_svc,最后将PC指向异常向量表对应位置。对于软中断,对应地址为0x80,因此PC跳转到0x80。
- PC到达0x80后执行跳转指令,跳转到中断处理函数。
- 中断处理函数也是一个函数,因此需要先入栈保存现场,之后进行相关的操作,最后出栈恢复现场。在出栈时,加上 "^" 符号可以自动将SPSR_svc的数据拷贝到CPSR恢复现场,同时出栈数据可以直接写到PC中,一步实现出栈、恢复现场、跳转。
实验代码如下:
.text
.global _start
_start:@异常向量表B MAIN @Reset 0x00B . @Undef 0x04B SWI_Handler @SWI 0x08B . @Prefetch Abort 0x0CB . @Data Abort 0x10B . @Reserved 0x14B . @IRQ 0x18B . @FIQ 0x20@MAIN中实现R3=R1+R2,并调用一次SWI
MAIN:MOV SP,#0x40000020 @初始化SP,这里是SVC模式下的SPMSR CPSR,#0x10 @将模式改为User模式,IRQ/FIQ使能MOV R1,#1MOV R2,#2SWI #1 @调用SWI,#1用于区分硬件ADD R3,R1,R2B STOP@SWI_Handler是SWI的中断处理函数,这里也实现R3=R1+R2的功能
SWI_Handler:STMFD SP!,{R1,R2,LR} @入栈保护现场MOV R1,#20MOV R2,#30ADD R3,R1,R2LDMFD SP!,{R1,R2,PC}^ @将LR的数据出栈到PC,并把SPSR的值拷贝到CPSR(^的作用)STOP:B STOP.end
协处理器指令
协处理器指令的分类可以分为:
- 数据运算指令CDP
- 存储器访问指令STC、LDC
- 寄存器传送指令MRC、MCR,用于在协处理器和ARM处理器中的寄存器进行数据交互。
伪指令
1、NOP
NOP是让程序什么都不干,暂停一个机器周期。最终编译之后NOP会被编译成MOV R0,R0
2、LDR
LDR的格式不同,含义也不同。当为 "LDR R1,[R2]" 这种格式时,LDR是一个指令;伪指令的情况有以下情况:
1、赋值任意32位数
当为 "LDR R1,=0x12345678" 这种格式时,LDR是一个伪指令,代表R1=0x12345678。该伪指令可以将任意32位数搬移到寄存器。LDR R1,=0x12345678的转换过程如下:
- 0x12345678将作为一个不被执行的机器码存放到内存中,这条机器码被存放在全部有效指令之后,在下图中存放在0x58处,因为0x54是最后一条有效指令。
- LDR的指令将被译码为 "LDR R1,[PC,#偏移值]" 这种格式,在下图中指令被存放在0x30,因为三级流水线的原因,此时PC=0x30+8,因此偏移值 = 0x20。
- 最终拿到的值是0x58地址当中的数据,就是0x12345678,实现了任意32位数据的赋值。
2、通过标号将地址写入寄存器
当为 "LDR R1,=STOP" 这种格式时,LDR是一个伪指令,代表将STOP标号的地址值存入R1中。
编译后的指令同样是转换成PC加偏移量模式,PC偏移量计算与LDR R1,=0x12345678这种计算方法一样。
3、通过标号将地址当中的值写入寄存器
当为 "LDR R1,STOP" 这种格式时,LDR是一个伪指令,代表将STOP标号的地址当中的值存入R1中。
编译后的指令同样是转换成PC加偏移量模式,PC偏移量计算与LDR R1,=0x12345678这种计算方法一样。
伪操作
伪操作通常以 "." 开头。
1、全局/局部声明
格式:
.global <符号名> .local <符号名>
作用:
将符号声明为全局/局部。
当声明为全局时,所有.s都能访问;当声明为局部时,只有当前.s能访问。
2、宏
格式:
.equ <宏名>,值
作用:
与C语言的#define一样,原值替代。
3、语句封装
格式:
.macro <符号>@汇编语句.endm
作用:
类似函数,函数名就是.macro后面跟的符号
4、条件编译
格式:
.if@汇编语句.endif
作用:
类似#if #endif,条件满足时才进行编译。
5、重复编译
格式:
.rept <次数>@汇编语句.endr
作用:
将区域中的汇编语句重复编译指定次数。
6、弱化符号
格式:
.weak <符号>
作用:
弱化指定的符号,当使用到该符号但未定义该符号时,编译器依旧不报错。
当弱化了符号,并且符号未定义时,编译器会将调用该符号的指令变为NOP,即:一个空操作。
7、申请空间
格式:
.word <初始化值> @32位,一个字.byte <初始化值> @8位,一个字节
.align <以多少字节对齐> @写3,代表以2^3对齐.space <申请字节数> <初始化值> @申请指定字节存放数据
.word作用:
在当前指令的地址位置申请空间,并初始化。
.byte作用:
注意:.byte申请空间后,需要再申请冗余空间来进行地址对齐。
.space作用:
注意:.space申请空间后,不一定需要.align来对齐,比如上述是12给字节空间,申请之后地址就是对齐的。
8、标注
格式:
.arm @告诉编译器这之后是arm指令
@ARM汇编指令.thumb @告诉编译器这之后是thumb指令
@Thumb汇编指令 .text @告诉编译器这之后是代码段.end @告诉编译器汇编代码已结束
相关文章:
5. ARM_指令集
概述 分类 汇编中的符号: 指令:能够编译生成一条32位机器码,并且能被处理器识别和执行伪指令:本身不是指令,编译器可以将其替换成若干条指令伪操作:不会生成指令,只是在编译阶段告诉编译器怎…...
Jenkins的pipeline Script的 每个组件的详细讲解
在Jenkins的Pipeline脚本中,各个组件的配置和Groovy的一些常用函数起到了决定性的作用,帮助开发人员控制自动化流程的执行。以下是对Jenkins Pipeline的主要组件和Groovy常用函数的详细讲解: 1. Jenkins Pipeline主要组件 1.1 agent 功能&…...
Tomcat 和 Netty 的区别及应用场景分析
在 Java Web 开发中,Tomcat 和 Netty 都是常见的网络框架,它们各自有着不同的设计理念和适用场景。本文将通过详细的对比和实际场景示例,帮助你理解 Tomcat 和 Netty 在功能、性能、架构等方面的差异,帮助你在实际开发中做出更合理…...
6.C操作符详解,深入探索操作符与字符串处理
C操作符详解,深入探索操作符与字符串处理 C语言往期系列文章目录 往期回顾: C语言是什么?编程界的‘常青树’,它的辉煌你不可不知VS 2022 社区版C语言的安装教程,不要再卡在下载0B/s啦C语言入门:解锁基础…...
生数科技发布 Vidu 1.5 新版本,引领视频大模型新潮流
在国内视频大模型领域,生数科技一直以创新和突破而备受瞩目。近日,生数科技再度发力,发布了 Vidu 1.5 新版本,为视频创作带来了全新的变革与机遇。 Vidu 1.5 新版本在多个方面展现出了卓越的性能和创新的特点。首先,它…...
CentOS 7 aarch64停止更新后安装gcc8 —— 筑梦之路
CentOS 7.9非X86架构系统生命周期结束后(2024-6-30)配置在线可用yum源 —— 筑梦之路_centos7.9 arm-CSDN博客 以前的做法 sudo yum install centos-release-scl-rh sudo yum install devtoolset-8-buildsudo yum install devtoolset-8-gdb sudo yum i…...
WPF下 DataGrid加入序号列
先上代码: <DataGrid Name"DGV" AutoGenerateColumns"False" Grid.Row"0" Grid.Column"0" HorizontalGridLinesBrush"RoyalBlue" VerticalGridLinesBrush"Tomato" CanUserAddRows"False&qu…...
iOS UI 自动化 手势右滑退出当前页面
1、TouchAction from appium.webdriver.common.touch_action import TouchAction# 获取屏幕的宽度和高度 screen_width driver.get_window_size()["width"] screen_height driver.get_window_size()["height"]# 定义滑动的起点和终点坐标 start_x 0 en…...
《MySQL 实战教程:从零开始到高手进阶》
当然可以。下面是一篇关于MySQL的学习指南,它适合初学者到中级用户,涵盖了MySQL的基础知识、安装步骤、基本命令以及一些高级功能。 MySQL 学习指南 1. 了解 MySQL MySQL 是一个关系型数据库管理系统(RDBMS),由瑞典…...
第27天 安全开发-PHP应用TP 框架路由访问对象操作内置过滤绕过核心漏洞
时间轴 演示案例 TP 框架-开发-配置架构&路由&MVC 模型 TP 框架-安全-不安全写法&版本过滤绕过 TP 框架-开发-配置架构&路由&MVC 模型 参考: https://www.kancloud.cn/manual/thinkphp5_1 1、配置架构-导入使用 去thinkphp官网可以看到&…...
应用系统开发(12) Zync中实现数字相敏检波
在 Xilinx Zynq 系列(如 Zynq-7000 或 Zynq UltraScale+)中实现数字相敏检波(DSP,Digital Synchronous Detection)可以通过硬件(PL部分,FPGA逻辑)和软件(PS部分,ARM Cortex-A 处理器)的协同工作来实现。以下是一个详细的设计方法,包括基本原理和 Zynq 的实现步骤。…...
栈Stack和队列Queue
目录 一、栈 (1)用数组实现 (2)用单链表实现 (3)用标注尾结点的单链表实现 (4)用双向链表实现 2、栈的实际应用 (1)改变元素的序列 (2&am…...
uniapp 微信小程序地图标记点、聚合点/根据缩放重合点,根据缩放登记显示气泡marik标点
如图,如果要实现上方的效果: 上方两个效果根据经纬度标记点缩放后有重复点会添加数量 用到的文档地址https://developers.weixin.qq.com/miniprogram/dev/api/media/map/MapContext.addMarkers.htmlMapContext.addMarkers(Object object) 添加标记点Ma…...
Percona XtraBackup备份docker版本mysql 5.7
my.cnf配置文件 [client] default_character_setutf8[mysqld] # 数据存储目录(必须手动指定) datadir/var/lib/mysql/data# 字符集 collation_server utf8_general_ci character_set_server utf8 # 二进制日志 server-id1 log_bin/var/log/mysql/binl…...
C++:关联式容器的介绍及map与set的使用
我们之前已经学习过string,vector,list,queue,priority_queue等容器,这些容器我们统称为序列式容器,因为它们的数据的逻辑结构呈线性。因为这些容器中存储的数据即便二者之间发生交换,也不会对原有的容器结构造成太大影响。 但上篇文章我们介…...
一文说清:Linux下C++静态库的封装和调用
一 引言 《一文说清:windows下C静态库的封装和调用》中说了: 静态库允许开发者在多个项目中复用代码,减少重复劳动,并增强程序的可维护性。并讲述了windows环境下创建、封装以及调用C静态库的过程。 本文则描述了,如…...
【Java 学习】数据类型、变量、运算符、条件控制语句
Java基础语法 1. 打印 Hello World !2. 变量类和数据类型2.1 什么是变量?什么是数据类型?2.2 常用的数据类型2.3 使用变量2.4 String 类数据类型2.4.1 String 类基本概念2.4.2 String 类的使用 3. 运算符3.1 算数运算符3.2 关系运算符3.3 逻辑运算符3.4 …...
【软考】系统架构设计师-数据库设计基础
数据库核心考点 三级模式-两级映射 外模式--视图 概念模式--表(模式、基本表) 内模式--物理文件 数据库设计 概念结构设计:属性冲突、命名冲突、结构冲突 逻辑结构设计:关系模式(层次模型、网络模型)…...
【Jmeter相关】
Jmeter 可以作为接口测试问题,也会涉及到性能相关的问题 一、JMeter中用户定义的变量(User Defined Variables)和用户参 数(User Parameters)的区别是什么? 在JMeter中都是用于定义和存储测试数据的方法,但它们有一…...
拍立淘按图搜索API接口系列,返回示例图参考
拍立淘按图搜索API接口允许用户通过上传图片来搜索相似的商品,该接口返回的通常是一个JSON格式的响应,其中包含了与上传图片相似的商品信息。以下是一个基于淘宝平台的拍立淘按图搜索API接口返回数据的JSON格式示例,同时提供对其关键字段的解…...
OSG开发笔记(三十二):深入理解相机视口、制作支持与主视图同步变换旋转的相机HUD
若该文为原创文章,未经允许不得转载 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/143852695 各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究 长沙红胖子Qt…...
2024RISC-V中国峰会 演讲幻灯片和视频回放均已公开
目录 一、幻灯片地址: 二、演讲视频: 一、幻灯片地址: RVSC2024/slides at main cnrv/RVSC2024 GitHub 二、演讲视频: RISC-V国际基金会的个人空间-RISC-V国际基金会个人主页-哔哩哔哩视频...
河道无人机雷达测流监测系统由哪几部分组成?
在现代水利管理中,河道无人机雷达监测系统正逐渐成为一种重要的工具,为河道的安全和管理提供了强大的技术支持。那么,这个先进的监测系统究竟由哪几部分组成呢? 河道无人机雷达监测系统工作原理 雷达传感器通过发射电磁波或激光束…...
28.<Spring博客系统⑤(部署的整个过程(CentOS))>
引入依赖 Spring-boot-maven-plugin 用maven进行打包的时候必须用到这个插件。看看自己pom.xml中有没有这个插件 并且看看配置正确不正常。 注:我们这个项目打的jar包在30MB左右。 <plugin><groupId>org.springframework.boot</groupId><artif…...
OpenAI震撼发布:桌面版ChatGPT,Windows macOS双平台AI编程体验!
【雪球导读】 「OpenAI推出ChatGPT桌面端」 OpenAI重磅推出ChatGPT桌面端,全面支持Windows和macOS系统!这款新工具为用户在日常生活和工作中提供了前所未有的无缝交互体验。对于那些依赖桌面端进行开发工作的专业人士来说,这一更新带来了令人…...
香港站群服务器有助于提升网站在搜索引擎中的排名
拥有253个IP的服务器通常被称为多IP站群服务器。这种服务器架构主要用于集中管理多个网站,允许网站管理员通过一个后台管理系统来高效管理和更新这些网站。 一、主要特点 集中管理:多IP站群服务器通过统一的后台管理系统,可以实现对多个网站…...
YOLOX:使用自己数据集训练模型及改进--1.YOLOX环境搭建及运行
YOLOX环境搭建及运行 YOLO X网络架构是继YOLO v5后,由旷视科技于2021年提出的新一代anthor-free模型,研究者将网络分为输入端、Backbone、PAFPN及Predication,并在Predication提出Decoupled Head、Anchor-free和Multi positives(后文会详细介绍)。 本篇文章介绍如何通过官…...
PyTorch使用教程-深度学习框架
PyTorch使用教程-深度学习框架 1. PyTorch简介 1.1-什么是PyTorch PyTorch是一个广泛使用的开源机器学习框架,特别适合深度学习的应用。它以其动态计算图而闻名,允许在运行时修改模型,使得实验和调试更加灵活。PyTorch提供了强大的GPU加…...
TON商城与Telegram App:生态融合与去中心化未来的精彩碰撞
随着区块链技术的快速发展,去中心化应用(DApp)逐渐成为了数字生态的重要组成部分。而Telegram作为全球领先的即时通讯应用,不仅仅满足于传统的社交功能,更在区块链领域大胆探索,推出了基于其去中心化网络的…...
“乐鑫组件注册表”简介
当启动一个新的开发项目时,开发者们通常会利用库和驱动程序等现有的代码资源。这种做法不仅节省时间,还简化了项目的维护工作。本文将深入探讨乐鑫组件注册表的概念及其核心理念,旨在指导您高效地使用和贡献组件。 概念解析 ESP-IDF 的架构…...
陕西省交通建设集团公司西商分公司网站/seo网站优化怎么做
需求:订单数据生成PDF文件 方案:思路是通过本地的Excle模版和订单数据生成PDF文件。 先把数据填入到Excle模版中,然后通过Excle转为PDF文件,输出PDF文件。 Excle模版内容如下: 生成PDF所需要的依赖如下:…...
济宁网站运营策略/产品推广广告
最方便的eclipse安装svn插件,没有之一,在eclipse插件市场安装即可: Help > Eclipse Marketplace... > 输入svn搜索插件安装 安装完成后,顶部菜单栏目就有SVN的菜单选项了...
电子商务网站建设管理答案/深圳网络营销推广外包
--------------------------------------------- 未能创建 Mutex。 说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。 异常详细信息: System.Inval…...
商标注册在哪个部门申请/网站功能优化
一、概述 推荐系统旨在预测用户可能喜欢什么,尤其是当有很多选择时。他们可以明确地向用户提供这些推荐,或者他们可能会在幕后工作,在不给用户选择的情况下选择要显示的内容。 无论哪种方式,“为什么”都很清楚:它们对某些类型的企业至关重要,因为它们可以让用户接触到他…...
合肥建设局网站官网/怎么做seo信息优化
问题: 公司有很多代码工程(几十个),如果将Jenkinsfile文件放置在每个代码工程里面,维护量很大,且当脚本发生必要的变更后,所有的工程代码中的这个文件都要重新修改。 为了解决这个问题,我编写了一个通用的Jenkinsfile脚本。将该文件设置为全局默认的脚本文件。 设置方…...
个人做网站怎么备案/中国十大搜索引擎网站
OPPO近日低调推出了多款新机,包括OPPO A79、A83、A73等,都是全面屏,不过都属于OPPO R11s旗舰机的低配版或者缩水版,都有着一张明星脸,但硬件缩水程度各有不同。今天小编主要带来OPPO A79和OPPO A73区别对比,…...