【C语言督学训练营 第二十一天】汇编语言零基础入门

news2024/11/18 17:26:30

文章目录

  • 前言
  • 1.C语言源文件转汇编
  • 2.汇编指令格式
  • 3.汇编常用指令
    • 3.1 相关寄存器
    • 3.2 常用指令
    • 3.3 数据传送指令
    • 3.4 算术/逻辑运算指令
    • 3.5 控制流指令
    • 3.6 条件码
  • 4.如何定义汇编中的变量
  • 5.选择循环汇编实战
  • 6.函数调用汇编实战
  • 7.C语言源文件转机器指令

前言

汇编语言是一种功能很强的程序设计语言,也是利用计算机所有硬件特性并能直接控制硬件的语言。学好以后可以做单片机、做操作系统、编译器,反正底层开发肯定是需要的。

汇编语言(assembly language)是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。在汇编语言中,用助记符代替机器指令的操作码,用地址符号或标号代替指令或操作数的地址。

在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植。

从上面可以看出汇编语言的强大之处,尔强任尔强,我们要做的是能够读懂汇编语言代码,能够了解到汇编语言中的基础知识,先看一道408专业课真题,代码部分给出了C语言代码与汇编代码的核心部分,我们要能从中看出这是干嘛的,然后解出题目即可!
在这里插入图片描述

1.C语言源文件转汇编

在进行C语言源文件转汇编之前,需要先配置环境变量,将我们之前安装的mingw64里面的bin目录配置到path变量中,这样就可以直接在黑窗口使用gcc命令了!配置环境变量教程网上一堆我就不啰嗦了,下面我说说如何生成汇编文件以C语言代码编译生成可执行文件的过程(这个过程在考纲之内,但是考试概率比较低)。

编译过程(了解即可,是大纲范围,考的概率不高)

  • 第一步: main.c–>编译器–》main.s文件(.s文件就是汇编文件,文件内是汇编代码)
  • 第二步:我们的main.s汇编文件—》汇编器—》main.obj
  • 第三步: main.obj文件–》链接器–》可执行文件exe

接下来让我们使用Clion生成汇编代码吧!
首先进入源文件所在目录(这里指的是mytest目录):
在这里插入图片描述
执行以下命令生成汇编文件(这种方式生成的与intel的汇编代码有一定的区别!):

gcc -S -fverbose-asm main.c

下面是生成与考研格式一样的汇编代码intel 32:

gcc -m32 -masm=intel -S -fverbose-asm main.c

在这里插入图片描述

2.汇编指令格式

在去看汇编指令前,我们来看下CPU是如何执行我们的程序的,如下图所示,我们编译后的可执行程序,也就是main.exe是放在代码段的,PC指针寄存器存储了一个指针,始终指向要执行的指令,读取了代码段的某一条指令后,会交给译码器来解析,这时候译码器就知道要做什么事情了,CPU 中的计算单元加法器不能直接对栈上的某个变量a,直接做加1操作的,需要首先将栈,也就是内存上的数据,加载到寄存器中,然后再用加法器做加1操作,再从寄存器搬到内存上去。
在这里插入图片描述
一条机器指令分为以下两部分:
操作码字段:表征指令的操作特性与功能(指令的唯一标识)︰不同的指令操作码不能相同。
地址码字段:指定参与操作的操作数的地址码。
指令中指定操作数存储位置的字段称为地址码,地址码中可以包含存储器地址。也可包含寄存器编号。指令中可以有一个、两个或者三个操作数,也可没有操作数, 根据一条指令有几个操作数地址,可将指令分为零地址指令。一地址指令、二地址指令、三地址指令。4个地址码的指令很少被使用(考研考不到,这里不列了)
在这里插入图片描述
在这里插入图片描述
二地址指令格式中,从操作数的物理位置来说有可归为三种类型

  • 寄存器-寄存器(RR)型指令:需要多个通用寄存器或个别专用寄存器,从寄存器中取操作数,把操作结果放入另一个寄存器,机器执行寄存器-寄存器型的指令非常快,不需要访存.
  • 寄存器-存储器(RS)型指令:执行此类指令时,既要访问内存单元,又要访问寄存器.
  • 存储器-存储器(SS)型指令:操作时都是涉及内存单元,参与操作的数都是放在内存里,从内存某单元中取操作数,操作结果存放至内存另一单元中,因此机器执行指令需要多次访问内存。

寄存器英文: register
存储器英文: storage

名称特征常见系统简称英文名
复杂指令集变长x86CISCComplex lnstruction Set Computer
精简指令集等长armRISCReduced lnstruction Set Computin

3.汇编常用指令

3.1 相关寄存器

在这里插入图片描述

3.2 常用指令

在这里插入图片描述

3.3 数据传送指令

在这里插入图片描述
在这里插入图片描述

3.4 算术/逻辑运算指令

在这里插入图片描述
在这里插入图片描述

3.5 控制流指令

在这里插入图片描述
在这里插入图片描述

3.6 条件码

编译器通过条件码(标志位)设置指令和各类转移指令来实现程序中的选择结构语句。
条件码(标志位)
除了整数寄存器,CPU还维护着一组条件码(标志位)寄存器,它们描述了最近的算术或逻辑运算操作的属性。可以检测这些寄存器来执行条件分支指令,最常用的条件码有:

  • CF:进(借)位标志。最近无符号整数加(减)运算后的进(借)位情况。有进(借)位,CF=1;否则CF=0。如(unsigned) t <(unsigned) a,因为判断大小是相减。
  • ZF:零标志。最近的操作的运算结算是否为0。若结果为0,ZF=1;否则ZF=0。如( t ==O) 。
  • SF:符号标志。最近的带符号数运算结果的符号。负数时,SF=1;
    否则SF=O。
  • OF:溢出标志。最近带符号数运算的结果是否溢出,若溢出,OF=1;否则OF=0。

可见,OF和SF对无符号数运算来说没有意义,而CF对带符号数运算来说没有意义。
在这里插入图片描述
常见的算术逻辑运算指令(add、sub、imul、 or、 and、shl、inc、dec、not、sal等)会设置条件码。但有两类指令只设置条件码而不改变任何其他寄存器,即cmp和test 指令, cmp指令和 sub指令的行为一样,test 指令与and指令的行为一样,但它们只设置条件码,而不更新目的寄存器。

注意:乘法溢出后,可以跳转到“溢出自陷指令”,例如 int 0x2e就是一条自陷指令,但是考研只需要掌握溢出,可以跳转到“溢出自陷指令”即可,不需要记自陷指令有哪些。

4.如何定义汇编中的变量

我们针对整型,整型数组,整型指针变量的赋值(浮点与字符等价的),对应的汇编进行解析,首先我们编写下面C代码:

#include <stdio.h>
int main() {
    int arr[3] = {1, 2, 3};
    int *p;
    int i = 5;
    int j = 10;
    i = arr[2];
    p = arr;
    printf("i=%d\n", i);
    return 0;
}

将其转换为汇编语言代码(考研出该类题目的话是以intel为基准,如果我们是windows系统,那么我们可以使用以下命令生成):

gcc -m32 -masm=intel -S -fverbose-asm main.c
  • 接下来我们来分析转换后的汇编代码,首先**#号代表注释**,我们从main标签位置开看即可。我们的C代码在让CPU去运行时,其实所有的变量名都已经消失了,实际是数据从一个空间,拿到另一个空间的过程
  • 栈内变量先定义在低地址还是高地址,取决于操作系统与CPU的组合,你的可能和我的不一样,因此不用去研究,没有意义(也不属于考研大纲范围)。
  • 我们访问所有变量的空间都是通过栈指针(esp时刻都存着栈指针,也可以称为栈顶指针)的偏移,来获取对应变量内存空间的数据的)。
	.file	"main.c"
	.intel_syntax noprefix
	.text
	.def	___main;	.scl	2;	.type	32;	.endef
	.section .rdata,"dr"
LC0:
	.ascii "i=%d\12\0"
	.text
	.globl	_main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
	push	ebp	 #
	mov	ebp, esp	 #,
	and	esp, -16	 #,
	sub	esp, 48	 #,
 # main.c:2: int main() {
	call	___main	 # #调用main函数
 # main.c:3:     int arr[3] = {1, 2, 3};
	mov	DWORD PTR [esp+24], 1	 # arr,# 把常量1放入栈指针(esp寄存器存的栈指针)偏移量24个字节
	mov	DWORD PTR [esp+28], 2	 # arr,
	mov	DWORD PTR [esp+32], 3	 # arr,
 # main.c:5:     int i = 5;
	mov	DWORD PTR [esp+44], 5	 # i,
 # main.c:6:     int j = 10;
	mov	DWORD PTR [esp+40], 10	 # j,# 把常量40放入栈指针(esp寄存器存的栈指针)偏移44个字节,这个位置属于变量j。
 # main.c:7:     i = arr[2];
	mov	eax, DWORD PTR [esp+32]	 # tmp89, arr #把后面地址指向的的数据拿到eax寄存器内。
	mov	DWORD PTR [esp+44], eax	 # i, tmp89
 # main.c:8:     p = arr;
	lea	eax, [esp+24]	 # tmp90,# 把后面的地址拿到eax寄存器内。
	mov	DWORD PTR [esp+36], eax	 # p, tmp90
 # main.c:9:     printf("i=%d\n", i);
	mov	eax, DWORD PTR [esp+44]	 # tmp91, i
	mov	DWORD PTR [esp+4], eax	 #, tmp91
	mov	DWORD PTR [esp], OFFSET FLAT:LC0	 #, #把LC0的地址放到寄存器栈指针指向的位置!
	call	_printf	 #
 # main.c:10:     return 0;
	mov	eax, 0	 # _10,
 # main.c:11: }
	leave	
	ret	
	.ident	"GCC: (x86_64-posix-sjlj-rev0, Built by MinGW-W64 project) 8.1.0"
	.def	_printf;	.scl	2;	.type	32;	.endef

大家转的汇编的偏移值可能和我这里有一些差异,这个没关系,大家理解变量赋值的汇编指令及原理即可,主要掌握的指令是 mov,还有lea,还有PTR。下面是ptr介绍

  • ptr – pointer(既指针)得缩写。
    汇编里面ptr是规定的字(既保留字),是用来临时指定类型的。(可以理解为, ptr是临时的类型转换,相当于C语言中的强制类型转换)
    如mov ax,bx;是把BX寄存器“里”的值赋予AX,由于二者都是寄存器,长度已定(word型),所以没有必要加“WORD”
    mov ax,word ptr [bx];是把内存地址等于“BX寄存器的值”的地方所存放的数据,赋予ax。由于只是给出一个内存地址,不知道希望赋予ax 的,是byte还是 word,所以可以用word明确指出;如果不用,既(mov ax, [bx];)则在8086中是默认传递一个字,既两个字节给ax。

intel 中的关键字:

  • dword ptr长字(4字节)
  • word ptr是双字节
  • byte ptr是一字节

5.选择循环汇编实战

先写一段源代码!

#include <stdio.h>
int main()
{
    int i=5;
    int j=10;
    if (i< j)
    {
        printf("i is small\n");
    }
    for(i=0;i<5;i++)
        printf( "this is loop\n");
    return 0;
}

生成汇编代码:

	.file	"main.c"
	.intel_syntax noprefix


	.text #这里是文字常量区,存放了我们的字符串常量!LC0 LC1是我们要打印字符串的起始地址!
	.def	___main;	.scl	2;	.type	32;	.endef
	.section .rdata,"dr"
LC0:
	.ascii "i is small\0"
LC1:
	.ascii "this is loop\0"
	.text
	.globl	_main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
	push	ebp	 #
	mov	ebp, esp	 #,
	and	esp, -16	 #,
	sub	esp, 32	 #,
 # main.c:3: {
	call	___main	 #
 # main.c:4:     int i=5;
	mov	DWORD PTR [esp+28], 5	 # i,
 # main.c:5:     int j=10;
	mov	DWORD PTR [esp+24], 10	 # j,
 # main.c:6:     if (i< j)
	mov	eax, DWORD PTR [esp+28]	 # tmp89, i
	cmp	eax, DWORD PTR [esp+24]	 # tmp89, j #前者减去后者,然后设置条件码
	jge	L2	 #,  #判断条件码L2 如果符合jge就跳转到L2标签,否则往下执行,jge是根据条件码ZF和SF来判断的。
 # main.c:8:         printf("i is small\n");
	mov	DWORD PTR [esp], OFFSET FLAT:LC0	 #,
	call	_puts	 #
L2:
 # main.c:10:     for(i=0;i<5;i++)
	mov	DWORD PTR [esp+28], 0	 # i,
 # main.c:10:     for(i=0;i<5;i++)
	jmp	L3	 # # 无条件跳转到L3
L4:
 # main.c:11:         printf( "this is loop\n");
	mov	DWORD PTR [esp], OFFSET FLAT:LC1	 #,
	call	_puts	 #
 # main.c:10:     for(i=0;i<5;i++)
	add	DWORD PTR [esp+28], 1	 # i,
L3:
 # main.c:10:     for(i=0;i<5;i++)
	cmp	DWORD PTR [esp+28], 4	 # i,比较变量i的值与4的大小,并设置条件码,如果小于等于则直接跳转到L4
	jle	L4	 #,
 # main.c:12:     return 0;
	mov	eax, 0	 # _11,
 # main.c:13: }
	leave	
	ret	
	.ident	"GCC: (x86_64-posix-sjlj-rev0, Built by MinGW-W64 project) 8.1.0"
	.def	_puts;	.scl	2;	.type	32;	.endef

这一块大家理解选择,循环的汇编指令及原理即可,主要掌握的指令是cmp,ige,jmp,jle等。以及了解一下字符串常量是存在文字常量区。

6.函数调用汇编实战

函数调用的汇编原理解析

先必须明确的一点是,函数栈是向下生长的。所谓向下生长,是指从内存高地址向低地址的路径延伸。于是,栈就有栈底和栈顶,栈顶的地址要比栈底的低。
对x86体系的CPU而言,寄存器ebp可称为帧指针或基址指针(base pointer),寄存器esp可称为栈指针(stack pointer) .
这里需要说明的几点如下。
(1) ebp在未改变之前始终指向栈帧的开始(也就是栈底),所以ebp的用途是在堆栈中寻址(寻址的作用会在下面详细介绍)。
(2) esp会随着数据的入栈和出栈而移动,即esp始终指向栈顶。

在这里插入图片描述
如图2所示,假设函数A调用函数B,称函数A为调用者,称函数B为被调用者,则函数调用过程可以描述如下:
(1)首先将调用者(A)的堆栈的基址(ebp)入栈,以保存之前任务的信息。
(2)然后将调用者(A)的栈顶指针(esp)的值赋给ebp,作为新的基址(即被调用者B的栈底)。原有函数的栈顶,是新函数的栈底。
(3)再后在这个基址(被调用者B的栈底)上开辟(一般用sub指令)相应的空间用作被调用者B的栈空间。
(4))函数B返回后,当前栈帧的ebp恢复为调用者A的栈顶(esp),使栈顶恢复函数B被调用前的位置;然后调用者A从恢复后的栈顶弹出之前的ebp值(因为这个值在函数调用前一步被压入堆栈)。
这样,ebp和 esp就都恢复了调用函数B前的位置,即栈恢复函数B调用前的状态。相当于(ret指令做了什么)

在这里插入图片描述
可以理解为以下一个过程!
在这里插入图片描述

先来写一段C语言有关函数的代码:

#include <stdio.h>
int add(int a,int b){
    int ret;
    ret = a + b;
    return ret;
}
int main() {
    int a, b,ret;
    int*p;
    a= 5;
    p = &a;
    b = *p + 2;
    ret = add(a, b);
    printf("add result=%d\n",ret);
    return 0;
}

生成汇编语言代码:

	.file	"main.c"
	.intel_syntax noprefix

	.text
	.globl	_add
	.def	_add;	.scl	2;	.type	32;	.endef
# add函数的入口
_add:
#把原有函数的栈基指针压栈
	push	ebp	 #
#修改栈基指针的指向(原栈顶将作为被调函数的栈基)
	mov	ebp, esp	 #,
# 栈顶向下移16个单位
	sub	esp, 16	 #,
 # main.c:4:     ret = a + b;
	mov	edx, DWORD PTR [ebp+8]	 # tmp93, a
	mov	eax, DWORD PTR [ebp+12]	 # tmp94, b
	add	eax, edx	 # tmp92, tmp93
	mov	DWORD PTR [ebp-4], eax	 # ret, tmp92
 # main.c:5:     return ret;
	mov	eax, DWORD PTR [ebp-4]	 # _4, ret
 # main.c:6: }
	leave	
	ret	 #函数返回,弹出压栈的指令返回地址回到main函数执行!
	.def	___main;	.scl	2;	.type	32;	.endef
	.section .rdata,"dr"
LC0:
	.ascii "add result=%d\12\0"
	.text
	.globl	_main
	.def	_main;	.scl	2;	.type	32;	.endef
# 当调用main函数时按照下面大小初始化栈空间
_main:
	push	ebp	 #
	mov	ebp, esp	 #,
	and	esp, -16	 #,
	sub	esp, 32	 #,
 # main.c:7: int main() {
	call	___main	 #
 # main.c:10:     a= 5;
	mov	DWORD PTR [esp+16], 5	 # a,
 # main.c:11:     p = &a;
 #把a变量的地址拿到eax寄存器内
	lea	eax, [esp+16]	 # tmp91,
# 把eax寄存器内存放的值放进地址为esp+28的空间内。
	mov	DWORD PTR [esp+28], eax	 # p, tmp91
 # main.c:12:     b = *p + 2;
 # 先找到指针变量p指向的地址,将其放进寄存器
	mov	eax, DWORD PTR [esp+28]	 # tmp92, p
 # 将寄存器指向地址里面的内容拿到寄存器内。
	mov	eax, DWORD PTR [eax]	 # _1, *p_5
 # main.c:12:     b = *p + 2;

 # eax寄存器内的值增加2
	add	eax, 2	 # tmp93,
#将计算结果放进[esp+24]空间内。
	mov	DWORD PTR [esp+24], eax	 # b, tmp93

# 下面是函数调用实参传递的经典动作,从而理解值传递是如何实现的!
 # main.c:13:     ret = add(a, b);
	mov	eax, DWORD PTR [esp+16]	 # a.0_2, a
	mov	edx, DWORD PTR [esp+24]	 # tmp94, b
	mov	DWORD PTR [esp+4], edx	 #, tmp94
	mov	DWORD PTR [esp], eax	 #, a.0_2
	call	_add	 #
# 将计算结果赋值进ret变量内。
	mov	DWORD PTR [esp+20], eax	 # ret, tmp95
 # main.c:14:     printf("add result=%d\n",ret);
	mov	eax, DWORD PTR [esp+20]	 # tmp96, ret
	mov	DWORD PTR [esp+4], eax	 #, tmp96
	mov	DWORD PTR [esp], OFFSET FLAT:LC0	 #,
	call	_printf	 #
 # main.c:15:     return 0;
	mov	eax, 0	 # _10,
 # main.c:16: }
	leave	
	ret	
	.ident	"GCC: (x86_64-posix-sjlj-rev0, Built by MinGW-W64 project) 8.1.0"
	.def	_printf;	.scl	2;	.type	32;	.endef

下图为main函数调用add函数的原理图!
在这里插入图片描述
这一部分大家理解指针变量的间接访问原理,函数调用的原理,到这里大家对于C语言的每一部分在机器上的运行已经非常清晰。这一部分主要掌握的指令是add,sub,call,ret等.

7.C语言源文件转机器指令

下面还需要掌握函数调用时机器码的偏移值,我们前面转的都只有汇编,没有含有机器码,如何得到机器码,需要执行下面两条指令.
第一条:gcc -m32 -g -o main main.c (Mac一致)
第二条:objdump --source main.exe >main.dump (Mac去掉.exe后缀,写为main即可)
如下为部分机器码,我们在考试时考的就是机器码!!!

main.exe:     file format pei-i386


Disassembly of section .text:

00401000 <___mingw_invalidParameterHandler>:
  401000:	f3 c3                	repz ret 
  401002:	8d b4 26 00 00 00 00 	lea    0x0(%esi,%eiz,1),%esi
  401009:	8d bc 27 00 00 00 00 	lea    0x0(%edi,%eiz,1),%edi

00401010 <_pre_c_init>:
  401010:	83 ec 1c             	sub    $0x1c,%esp
  401013:	31 c0                	xor    %eax,%eax
  401015:	66 81 3d 00 00 40 00 	cmpw   $0x5a4d,0x400000
  40101c:	4d 5a 
  40101e:	c7 05 8c 53 40 00 01 	movl   $0x1,0x40538c
  401025:	00 00 00 
  401028:	c7 05 88 53 40 00 01 	movl   $0x1,0x405388
  40102f:	00 00 00 
  401032:	c7 05 84 53 40 00 01 	movl   $0x1,0x405384
  401039:	00 00 00 
  40103c:	c7 05 20 50 40 00 01 	movl   $0x1,0x405020
  401043:	00 00 00 
  401046:	74 49                	je     401091 <_pre_c_init+0x81>
  401048:	a3 08 50 40 00       	mov    %eax,0x405008
  40104d:	a1 98 53 40 00       	mov    0x405398,%eax
  401052:	85 c0                	test   %eax,%eax
  401054:	74 2d                	je     401083 <_pre_c_init+0x73>
  401056:	c7 04 24 02 00 00 00 	movl   $0x2,(%esp)
  40105d:	e8 4a 15 00 00       	call   4025ac <___set_app_type>
  401062:	e8 4d 15 00 00       	call   4025b4 <___p__fmode>
  401067:	8b 15 a8 53 40 00    	mov    0x4053a8,%edx
  40106d:	89 10                	mov    %edx,(%eax)
  40106f:	e8 dc 05 00 00       	call   401650 <__setargv>
  401074:	83 3d 1c 30 40 00 01 	cmpl   $0x1,0x40301c
  40107b:	74 63                	je     4010e0 <_pre_c_init+0xd0>
  40107d:	31 c0                	xor    %eax,%eax
  40107f:	83 c4 1c             	add    $0x1c,%esp
  401082:	c3                   	ret    
  401083:	c7 04 24 01 00 00 00 	movl   $0x1,(%esp)
  40108a:	e8 1d 15 00 00       	call   4025ac <___set_app_type>
  40108f:	eb d1                	jmp    401062 <_pre_c_init+0x52>
  401091:	8b 15 3c 00 40 00    	mov    0x40003c,%edx
  401097:	81 ba 00 00 40 00 50 	cmpl   $0x4550,0x400000(%edx)

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

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

相关文章

WebDAV之π-Disk派盘 + CX文件管理器

CX文件管理器是一款好用的文件管理工具。它的功能非常的丰富,它能满足用户对文件管理的需求,而且功能也是一目了然,可以帮助用户快速的对文件进行操作。这款软件还支持SFTP、WebDAV、FTP等下载访问方式。手机和电脑在同一局域网下,可以使用FTP或派盘从你的电脑直接访问手机…

selenium页面切换操作

selenuim页面切换 webdriver只能在一个页面里对元素进行识别和定位。如果有多个页面操作的时候&#xff0c;要先进行页面切换。 切换分两种 1 iframe内嵌页面切换&#xff08;框架集切换&#xff09; # 1 获取iframe标签 iframe driver.find_element_by_tag_name(iframe) …

echarts绘制甘特图

说在前面 项目上有需求&#xff0c;需要在大屏上展示进度甘特图&#xff0c;调研了DHTMLX和普加甘特图&#xff0c;效果都不是特别符合需求现状&#xff0c;查询了一些博客&#xff0c;决定使用echarts来绘制甘特图。 实现效果展示 实现思路分析 1、应该采用柱状图&#xff…

LeetCode404. 左叶子之和

404. 左叶子之和 文章目录 [404. 左叶子之和](https://leetcode.cn/problems/sum-of-left-leaves/)一、题目二、题解方法一&#xff1a;递归方法二&#xff1a;迭代 一、题目 给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 示例 1&#xff1a; 输入: root [3,9…

个人信息保护合规审计如何做?

8月3日&#xff0c;为指导、规范个人信息保护合规审计活动&#xff0c;根据《中华人民共和国个人信息保护法》等法律法规&#xff0c;国家互联网信息办公室就《个人信息保护合规审计管理办法&#xff08;征求意见稿&#xff09;》&#xff08;简称《办法》&#xff09;及配套的…

【Apifox】Apifox设置全局Token:

文章目录 一、获取登录Token和设置全局变量&#xff1a;二、设置全局参数&#xff1a;三、效果&#xff1a; 一、获取登录Token和设置全局变量&#xff1a; 二、设置全局参数&#xff1a; 三、效果&#xff1a;

盘点7月Sui生态发展,了解Sui的近期成长历程!

自5月Sui主网上线三个月以来&#xff0c;7月是Sui网络进行最多次重要更新的一个月&#xff0c;Sui网络和生态正呈指数形式不断向上发展。为吸引更多的项目或开发者加入生态构建以及活跃用户参与生态&#xff0c;Sui基金会推出了Builder House、黑客松、Bullshark Quests、NFT再…

数据库:MYSQL参数max_allowed_packet 介绍

1、参数作用 max_allowed_packet参数是指mysql服务器端和客户端在一次传送数据包的过程当中最大允许的数据包大小。如果超过了设置的最大长度,则会数据库保持数据失败。 2、问题场景 ● 有时候业务的需要,可能会存在某些字段数据长度非常大(比如富文本编辑器里面的内容),…

基于Java的学生管理系统设计与实现

一、系统功能介绍 基于Java的学生管理系统&#xff0c;本系统包括学生信息管理、学生成绩管理、县教育信息管理、个人资料管理等功能。 二、相关页面展示 以下是页面展示&#xff1a; 1 登录页面 2 首页页面页面 3 学生成绩查询页面 4 本校成绩排行页面 5 管理员学生成绩管…

【Apollo学习笔记】—— Cyber RT之调度

文章目录 前言相关代码整理 调度介绍Cyber RT的改进实时操作系统资源限制&优先级协程 Cyber RT调度策略任务窃取两种任务类型componen组件自定义任务 Cyber调度实践配置文件DAG文件cyber_launch文件component组件BUILD文件 问题参考 前言 本文是对Cyber RT的学习记录,文章可…

4G WWAN设备类型

WWAN设备类型 USB dongle是设备接入互联网的重要方式之一&#xff0c;典型的通过USB接口与主设备连接&#xff0c;然后主设备通过4G/5G接入互联网&#xff0c;作为移动宽带设备&#xff0c;它有那些设备类型及暴露方式呢&#xff1f; 移动宽带设备类型&#xff1a;ModemManage…

无涯教程-Lua - nested语句函数

Lua编程语言允许在另一个循环中使用一个循环。以下部分显示了一些示例来说明这一概念。 nested loops - 语法 Lua中嵌套for循环语句的语法如下- for init,max/min value, increment dofor init,max/min value, incrementdostatement(s)endstatement(s) end Lua编程语言中的…

Podman权限问题导致的403报错思路与解决

问题 podman运行镜像&#xff0c;端口映射、卷映射无误&#xff0c;但在运行访问测试容器内http接口报错403. 查阅系统日志&#xff0c;存在多处容器相关的selinux访问被拒绝错误&#xff0c;sealert提示需要为几个进程的对象添加临时规则。 考虑是否为selinux问题&#xff…

语义分割文献整理

2014年文献 1.论文题目《Semantic Image Segmentation with Deep Convolutional Nets and Fully Connected CRFs》 1.1.网络别名《DeepLabV1》 1.2.论文引用 Chen L C, Papandreou G, Kokkinos I, et al. Semantic image segmentation with deep convolutional nets and fu…

AI赋能转型升级 助力打造“数智辽宁”——首次大模型研讨沙龙在沈成功举行

当前&#xff0c;以“ChatGPT”为代表的大模型正在引领新一轮全球人工智能技术发展浪潮&#xff0c;推动人工智能从以专用小模型定制训练为主的“手工作坊时代”&#xff0c;迈入以通用大模型预训练为主的“工业化时代”&#xff0c;正不断加速实体经济智能化升级&#xff0c;深…

(自控原理)控制系统的数学模型

目录 一、时域数学模型 1、线性元件微分方程的建立 2、微分方程的求解方法​编辑 3、非线性微分方程的线性化 二、复域数学模型 1、传递函数的定义 2、传递函数的标准形式 3、系统的典型环节的传递函数 4、传递函数的性质 5、控制系统数学模型的建立 6、由传递函数求…

【C++】带三维重建和还原的RIS/PACS源码

【PACS】集成三维影像后处理功能&#xff0c;包括三维多平面重建、三维容积重建、三维表面重建、三维虚拟内窥镜、最大/小密度投影、心脏动脉钙化分析等功能。系统功能强大&#xff0c;代码完整。 一、RIS/PACS系统简介 RIS/PACS系统在预约登记、分诊叫号、技师检查、诊断报告…

面向开发人员的远程桌面:随时随地安全编写代码

随着数字世界的不断发展&#xff0c;传统意义上的“工作场所”概念正在发生重大转变。这种转变在科技行业尤其明显&#xff0c;开发人员和软件工程师越来越倾向于选择远程或混合办公模式。 在这次重大转变中&#xff0c;远程桌面软件经证明是一项足以影响远程办公的技术。通过…

YOLOv5改进系列(18)——更换Neck之AFPN(全新渐进特征金字塔|超越PAFPN|实测涨点)

【YOLOv5改进系列】前期回顾: YOLOv5改进系列(0)——重要性能指标与训练结果评价及分析 YOLOv5改进系列(1)——添加SE注意力机制

使用Golang实现一套流程可配置,适用于广告、推荐系统的业务性框架——简单应用

在诸如广告、推荐等系统中&#xff0c;我们往往会涉及过滤、召回和排序等过程。随着系统业务变得复杂&#xff0c;代码的耦合和交错会让项目跌入难以维护的深渊。于是模块化设计是复杂系统的必备基础。这篇文章介绍的业务框架脱胎于线上多人协作开发、高并发的竞价广告系统&…