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

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_指令集

概述 分类 汇编中的符号&#xff1a; 指令&#xff1a;能够编译生成一条32位机器码&#xff0c;并且能被处理器识别和执行伪指令&#xff1a;本身不是指令&#xff0c;编译器可以将其替换成若干条指令伪操作&#xff1a;不会生成指令&#xff0c;只是在编译阶段告诉编译器怎…...

Jenkins的pipeline Script的 每个组件的详细讲解

在Jenkins的Pipeline脚本中&#xff0c;各个组件的配置和Groovy的一些常用函数起到了决定性的作用&#xff0c;帮助开发人员控制自动化流程的执行。以下是对Jenkins Pipeline的主要组件和Groovy常用函数的详细讲解&#xff1a; 1. Jenkins Pipeline主要组件 1.1 agent 功能&…...

Tomcat 和 Netty 的区别及应用场景分析

在 Java Web 开发中&#xff0c;Tomcat 和 Netty 都是常见的网络框架&#xff0c;它们各自有着不同的设计理念和适用场景。本文将通过详细的对比和实际场景示例&#xff0c;帮助你理解 Tomcat 和 Netty 在功能、性能、架构等方面的差异&#xff0c;帮助你在实际开发中做出更合理…...

6.C操作符详解,深入探索操作符与字符串处理

C操作符详解&#xff0c;深入探索操作符与字符串处理 C语言往期系列文章目录 往期回顾&#xff1a; C语言是什么&#xff1f;编程界的‘常青树’&#xff0c;它的辉煌你不可不知VS 2022 社区版C语言的安装教程&#xff0c;不要再卡在下载0B/s啦C语言入门&#xff1a;解锁基础…...

生数科技发布 Vidu 1.5 新版本,引领视频大模型新潮流

在国内视频大模型领域&#xff0c;生数科技一直以创新和突破而备受瞩目。近日&#xff0c;生数科技再度发力&#xff0c;发布了 Vidu 1.5 新版本&#xff0c;为视频创作带来了全新的变革与机遇。 Vidu 1.5 新版本在多个方面展现出了卓越的性能和创新的特点。首先&#xff0c;它…...

CentOS 7 aarch64停止更新后安装gcc8 —— 筑梦之路

CentOS 7.9非X86架构系统生命周期结束后&#xff08;2024-6-30&#xff09;配置在线可用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加入序号列

先上代码&#xff1a; <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的学习指南&#xff0c;它适合初学者到中级用户&#xff0c;涵盖了MySQL的基础知识、安装步骤、基本命令以及一些高级功能。 MySQL 学习指南 1. 了解 MySQL MySQL 是一个关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;由瑞典…...

第27天 安全开发-PHP应用TP 框架路由访问对象操作内置过滤绕过核心漏洞

时间轴 演示案例 TP 框架-开发-配置架构&路由&MVC 模型 TP 框架-安全-不安全写法&版本过滤绕过 TP 框架-开发-配置架构&路由&MVC 模型 参考&#xff1a; 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

目录 一、栈 &#xff08;1&#xff09;用数组实现 &#xff08;2&#xff09;用单链表实现 &#xff08;3&#xff09;用标注尾结点的单链表实现 &#xff08;4&#xff09;用双向链表实现 2、栈的实际应用 &#xff08;1&#xff09;改变元素的序列 &#xff08;2&am…...

uniapp 微信小程序地图标记点、聚合点/根据缩放重合点,根据缩放登记显示气泡marik标点

如图&#xff0c;如果要实现上方的效果&#xff1a; 上方两个效果根据经纬度标记点缩放后有重复点会添加数量 用到的文档地址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] # 数据存储目录&#xff08;必须手动指定&#xff09; 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等容器&#xff0c;这些容器我们统称为序列式容器&#xff0c;因为它们的数据的逻辑结构呈线性。因为这些容器中存储的数据即便二者之间发生交换&#xff0c;也不会对原有的容器结构造成太大影响。 但上篇文章我们介…...

一文说清:Linux下C++静态库的封装和调用

一 引言 《一文说清&#xff1a;windows下C静态库的封装和调用》中说了&#xff1a; 静态库允许开发者在多个项目中复用代码&#xff0c;减少重复劳动&#xff0c;并增强程序的可维护性。并讲述了windows环境下创建、封装以及调用C静态库的过程。 本文则描述了&#xff0c;如…...

【Java 学习】数据类型、变量、运算符、条件控制语句

Java基础语法 1. 打印 Hello World !2. 变量类和数据类型2.1 什么是变量&#xff1f;什么是数据类型&#xff1f;2.2 常用的数据类型2.3 使用变量2.4 String 类数据类型2.4.1 String 类基本概念2.4.2 String 类的使用 3. 运算符3.1 算数运算符3.2 关系运算符3.3 逻辑运算符3.4 …...

【软考】系统架构设计师-数据库设计基础

数据库核心考点 三级模式-两级映射 外模式--视图 概念模式--表&#xff08;模式、基本表&#xff09; 内模式--物理文件 数据库设计 概念结构设计&#xff1a;属性冲突、命名冲突、结构冲突 逻辑结构设计&#xff1a;关系模式&#xff08;层次模型、网络模型&#xff09…...

【Jmeter相关】

Jmeter 可以作为接口测试问题&#xff0c;也会涉及到性能相关的问题 一、JMeter中用户定义的变量(User Defined Variables&#xff09;和用户参 数&#xff08;User Parameters&#xff09;的区别是什么? 在JMeter中都是用于定义和存储测试数据的方法&#xff0c;但它们有一…...

拍立淘按图搜索API接口系列,返回示例图参考

拍立淘按图搜索API接口允许用户通过上传图片来搜索相似的商品&#xff0c;该接口返回的通常是一个JSON格式的响应&#xff0c;其中包含了与上传图片相似的商品信息。以下是一个基于淘宝平台的拍立淘按图搜索API接口返回数据的JSON格式示例&#xff0c;同时提供对其关键字段的解…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...