ARM uboot源码分析3-启动第一阶段

news2024/11/16 19:41:48

一、start.S 解析7

总结回顾:lowlevel_init.S 中总共做了哪些事情:
检查复位状态、IO 恢复、关看门狗、开发板供电锁存、时钟初始化、DDR 初始化、串口初始化并打印 ‘O’、tzpc 初始化、打印 ‘K’。

在这里插入图片描述

其中值得关注的:关看门狗、开发板供电锁存、时钟初始化、DDR初始化、打印"OK"。


1、再次设置栈(DDR 中的栈)

在这里插入图片描述

(1) 再次开发板供电锁存。第一,做 2 次供电锁存是不会错的;第二,做 2 次则第 2 次无意义;做代码移植时有一个古怪谨慎保守策略:就是尽量添加代码而不要删除代码。


在这里插入图片描述

(2) 之前在调用 lowlevel_init 程序前,设置过 1 次栈(start.S 284-287行),那时候因为 DDR 尚未初始化,因此程序执行都是在 SRAM 中,所以在 SRAM 中分配了一部分内存作为栈。

本次因为 DDR 已经被初始化了,因此要把栈挪移到 DDR 中,所以要重新设置栈,这是第二次(start.S 297-299 行);这里实际设置的栈的地址是 33E00000,刚好在 uboot 的代码段的下面紧挨着。

在这里插入图片描述

在这里插入图片描述


(3) 为什么要再次设置栈?因为 DDR 已经初始化了,已经有大片内存可以用了,没必要再把栈放在 SRAM 中可怜兮兮的了;原来 SRAM 中内存大小空间有限,栈放在那里要注意不能使用过多的栈,否则栈会溢出,我们及时将栈迁移到 DDR 中,也是为了尽可能避免栈使用时候的小心翼翼。

感慨:uboot 的启动阶段主要技巧就在于,小范围内有限条件下的辗转腾挪。


2、再次判断当前地址以决定是否重定位

在这里插入图片描述

(1) 再次用相同的代码判断运行地址是在 SRAM 中还是 DDR 中,不过本次判断的目的不同(上次判断是为了决定是否要执行初始化时钟和 DDR 的代码),这次判断是为了决定是否进行 uboot 的 relocate 重定向

(2) 冷启动时,当前情况是:uboot 的前一部分(16kb 或者 8kb)开机自动从 SD 卡加载到 SRAM 中正在运行,uboot 的第二部分(其实第二部分是整个 uboot 文件)还躺在 SD 卡的某个扇区开头的 N 个扇区中。此时 uboot 的第一阶段已经即将结束了(第一阶段该做的事基本做完了),结束之前要把第二部分(整个 uboot 文件)加载到 DDR 中链接地址处(0x33e00000),这个加载过程就叫重定位。


二、uboot 重定位详解

(1) 0xD0037488 这个内存地址在 SRAM 中,这个地址中的值是被硬件自动设置的。硬件根据我们实际电路中 SD 卡在哪个通道中,会将这个地址中的值设置为相应的数字。譬如我们从 SD0 通道启动时,这个值为 EB000000 ;从 SD2 通道启动时,这个值为 EB200000

《S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf》:

在这里插入图片描述


《S5PV210_UM_REV1.1.pdf》:
在这里插入图片描述


(2) 我们在 start.S 的 260 行确定了从 MMCSD 启动,然后又在 278 行将 #BOOT_MMCSD 写入了 INF_REG3 寄存器中存储着。然后又在 322 行读出来,再和 #BOOT_MMCSD 去比较,确定是从 MMCSD 启动。最终跳转到 mmcsd_boot 函数中去执行重定位动作。

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


(3) 真正的重定位是通过调用 movi_bl2_copy 函数完成的,在 uboot/cpu/s5pc11x/movi.c 中。是一个 C 语言的函数。
在这里插入图片描述


(4) copy_bl2(2, MOVI_BL2_POS, MOVI_BL2_BLKCNT, CFG_PHY_UBOOT_BASE, 0);
分析参数:2 表示通道 2;MOVI_BL2_POS 是 uboot 的第二部分在 SD 卡中的开始扇区,这个扇区数字必须和烧录 uboot 时烧录的位置相同;MOVI_BL2_BLKCNT 是 uboot 的长度占用的扇区数;CFG_PHY_UBOOT_BASE 是重定位时将 uboot 的第二部分复制到 DDR 中的起始地址(33E00000)。

在这里插入图片描述

在这里插入图片描述

《S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf》:

在这里插入图片描述


三、start.S 解析8

1、什么是虚拟地址、物理地址

(1) 物理地址就是物理设备设计生产时赋予的地址。像裸机中使用的寄存器的地址就是 CPU 设计时指定的,这个就是物理地址。物理地址是硬件编码的,是设计生产时确定好的,一旦确定了就不能改了。

(2) 一个事实就是:寄存器的物理地址是无法通过编程修改的,是多少就是多少,只能通过查询数据手册获得并操作。坏处就是不够灵活。一个解决方案就是使用虚拟地址。

(3) 虚拟地址意思就是,在我们软件操作和硬件被操作之间增加一个层次,叫做虚拟地址映射层。有了虚拟地址映射后,软件操作只需要给虚拟地址硬件操作还是用原来的物理地址映射层建立一个虚拟地址到物理地址的映射表。当我们软件运行的时候,软件中使用的虚拟地址在映射表中查询,得到对应的物理地址再发给硬件去执行(虚拟地址到物理地址的映射是不可能通过软件来实现的)。

在这里插入图片描述


2、MMU 单元的作用

(1) MMU 就是 memory management unit,内存管理单元。MMU实际上是 SoC 中一个硬件单元,它的主要功能就是实现虚拟地址到物理地址的映射

(2) MMU 芯片在 CP15 协处理器中进行控制,也就是说要操控 MMU 进行虚拟地址映射,方法就是对 cp15 协处理器的寄存器进行编程。


3、地址映射的额外收益1:访问控制

(1) 访问控制就是:在管理上对内存进行分块,然后每块进行独立的虚拟地址映射,然后在每一块的映射关系中同时还实现了访问控制(对该块可读、可写、只读、只写、不可访问等控制)。

(2) 回想在 C 语言中编程中经常会出现一个错误:Segmentation fault。实际上这个段错误就和 MMU 实现的访问控制有关。当前程序只能操作自己有权操作的地址范围(若干个内存块),如果当前程序指针出错访问了不该访问的内存块,则就会触发段错误。


4、地址映射的额外收益2:cache

(1) cache 的工作和虚拟地址映射有关系。

(2) cache 是快速缓存,意思就是比 CPU 慢但是比 DDR 块。CPU 嫌 DDR 太慢了,于是乎把一些 DDR 中常用的内容事先读取缓存在 cache 中,然后 CPU 每次需要找东西时先在 cache 中找。如果 cache 中有就直接用 cache 中的;如果 cache 中没有,才会去 DDR 中寻找。

参考阅读


四、start.S 解析9

在这里插入图片描述

1、使能域访问(cp15的c3寄存器)

(1) cp15协处理器内部有 c0 到 c15 共 16 个寄存器,这些寄存器每一个都有自己的作用。我们通过 mrc 和 mcr 指令来访问这些寄存器。所谓的操作 cp 协处理器其实就是操作 cp15 的这些寄存器。

(2) c3 寄存器在 mmu 中的作用是控制域访问。域访问是和 MMU 的访问控制有关的。


2、设置 TTB(cp15 的 c2 寄存器)

(1) TTB 就是 translation table base,转换表基地址。首先要明白什么是 TT(translation table转换表),TTB其实就是转换表的基地址。

(2) 转换表是建立一套虚拟地址映射的关键。转换表分 2 部分,表索引和表项。表索引对应虚拟地址,表项对应物理地址。一对表索引和表项构成一个转换表单元,能够对一个内存块进行虚拟地址转换。(映射表基本规定中,规定了内存映射和管理是以块为单位的,至于块有多大,要看你的 MMU 的支持和你自己的选择。在 ARM 中支持 3 种块大小,细表 1KB、粗表 4KB、段 1MB)。真正的转换表就是由若干个转换表单元构成的,每个单元负责1个内存块,总体的转换表负责整个内存空间(0 - 4G)的映射。

在这里插入图片描述


(3) 整个建立虚拟地址映射的主要工作就是建立这张转换表。

(4) 转换表是放置在内存中的,放置时要求起始地址在内存中要 xx 位对齐。转换表不需要软件去干涉使用,而是将基地址 TTB 设置到 cp15 的 c2 寄存器中,然后 MMU 工作时会自动去查转换表。


3、使能 MMU 单元(cp15 的 c1 寄存器)

在这里插入图片描述

(1) cp15 的 c1 寄存器的 bit 0 控制 MMU 的开关。只要将这一个 bit 置 1 ,即可开启 MMU 。开启 MMU 之后,上层软件层的地址就必须经过TT的转换才能发给下层物理层去执行。


4、找到映射表待分析

(1) 通过符号查找,确定转换表在 lowlevel_init.S 文件的 593 行。
在这里插入图片描述

在这里插入图片描述


五、start.S 解析10

在这里插入图片描述

宏观上理解转换表:整个转换表可以看作是一个 int 类型的数组,数组中的一个元素就是一个表索引和表项的单元。数组中的元素值就是表项,这个元素的数组下标就是表索引。

在这里插入图片描述

ARM 的段式映射中,长度为 1MB,因此一个映射单元只能管 1MB 内存,那我们整个 4G 范围内需要 4G/1MB = 4096 个映射单元,也就是说这个数组的元素个数是 4096.实际上我们做的时候并没有依次单个处理这 4096 个单元,而是把 4096 个分成几部分,然后每部分用 for 循环做相同的处理。


1、宏 FL_SECTION_ENTRY

在这里插入图片描述

.macro FL_SECTION_ENTRY base,ap,d,c,b
	.word (\base << 20) | (\ap << 10) | \
	      (\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)
.endm

我们可以看到,base << 20,意思就是,左移 20位,就是以 M (k,M,G…)字节为单位进行划分;

因此 base 如果是 5,FL_SECTION_ENTRY 5,ap,d,c,b 就映射起始地址为 5M(到 6M,因为每一个表项的大小是 1 M)的地址空间,后面的 ap,d,c,b 是映射的这段地址区域的访问控制信息。


2.

在这里插入图片描述

对于上面这段代码的理解:

.set __base,0,把 __base 设置为 0。
.rept ... .endr 之间的语句,是一个循环;每次 __base 递增 1,循环次数为 0x100(256)。

base 的取值映射表的“表项”(物理地址)映射表的“表索引”(虚拟地址,以 M 字节划分)
00x0000_0000 (0 << 20)0x0 (M)
10x0010_0000 (1 << 20)0x1 (M)
20x0020_0000 (2 << 20)0x2 (M)
30x0030_0000 (3 << 20)0x3 (M)
… (M)
0xFF0x0FF0_0000 (0xFF << 20)0xFF (M)

因此,这段循环就映射了一段物理地址空间: 0x0 ~ (0x1000,0000 - 1)。因此,这段循环映射的物理地址范围是:0 ~ 256M - 1,总共拥有的表索引是 0 ~ 255。

通过 uboot 的注释可以看到,这段地址区域,确实是给 iRAM 空间使用的。
在这里插入图片描述


3.

接着我们继续分析接下来的 uboot 代码。
在这里插入图片描述

base 的取值映射表的“表项”(物理地址)映射表的“表索引”(虚拟地址,以 M 字节划分)
null00x100 (M)
null00x101 (M)
null00x102 (M)
null00x103 (M)
… (M)
null00x1FF (M)

虚拟地址范围 0x1000_0000 ~ 0x1FFF_FFFF,将其映射到物理地址 0 ,即无效地址。

如下图可以看到,物理地址 0x1000_0000 ~ 0x1FFF_FFFF 确实是保留区,不应该被访问。

所以将虚拟地址范围 0x1000_0000 ~ 0x1FFF_FFFF映射为无效地址,是符合逻辑的。

在这里插入图片描述


4.

在这里插入图片描述

base 的取值映射表的“表项”(物理地址)映射表的“表索引”(虚拟地址,以 M 字节划分)
0x2000x2000_00000x200 (M)
0x2010x2010_00000x201 (M)
0x2020x2020_00000x202 (M)
0x2030x2030_00000x203 (M)
… (M)
0x5FF0x5FF0_00000x5FF (M)

虚拟地址范围 0x2000_0000 ~ 0x5FFF_FFFF,将其映射到物理地址 0x2000_0000 ~ 0x5FFF_FFFF 。

如下图可以看到,物理地址 0x2000_0000 ~ 0x5FFF_FFFF 是 DDR 内存区域。

在这里插入图片描述

关于 DRAM 内存空间的区域,uboot 指定的地址详情如下图。详情可以参考博文:链接地址。
在这里插入图片描述


5.

在这里插入图片描述

base 的取值映射表的“表项”(物理地址)映射表的“表索引”(虚拟地址,以 M 字节划分)
null00x600 (M)
null00x601 (M)
null00x602 (M)
null00x603 (M)
… (M)
null00x7FF (M)

虚拟地址范围 0x6000_0000 ~ 0x7FFF_FFFF,将其映射到物理地址 0 ,即无效地址。

如下图可以看到,物理地址 0x6000_0000 ~ 0x7FFF_FFFF 确实是 uboot 中未设置的 DDR 区域,不应该被访问。

所以将虚拟地址范围 0x6000_0000 ~ 0x7FFF_FFFF 映射为无效地址,是符合逻辑的。
在这里插入图片描述


6.

在这里插入图片描述

base 的取值映射表的“表项”(物理地址)映射表的“表索引”(虚拟地址,以 M 字节划分)
0x8000x8000_00000x800 (M)
0x8010x8010_00000x801 (M)
0x8020x8020_00000x802 (M)
0x8030x8030_00000x803 (M)
… (M)
0xaFF0xaFF0_00000xaFF (M)

虚拟地址范围 0x8000_0000 ~ 0xaFFF_FFFF,将其映射到物理地址 0x8000_0000 ~ 0xaFFF_FFFF 。

如下图可以看到,物理地址 0x8000_0000 ~ 0xaFFF_FFFF 是 SROMC_BANK 区域。

在这里插入图片描述


7.

在这里插入图片描述

base 的取值映射表的“表项”(物理地址)映射表的“表索引”(虚拟地址,以 M 字节划分)
0xb000xb000_00000xb00 (M)
0xb010xb010_00000xb01 (M)
0xb020xb020_00000xb02 (M)
0xb030xb030_00000xb03 (M)
… (M)
0xbFF0xbFF0_00000xbFF (M)

虚拟地址范围 0xb000_0000 ~ 0xbFFF_FFFF,将其映射到物理地址 0xb000_0000 ~ 0xbFFF_FFFF 。

如下图可以看到,物理地址 0xb000_0000 ~ 0xbFFF_FFFF 是 ONENAND/NAND 区域。

在这里插入图片描述


8.

在这里插入图片描述

base 的取值映射表的“表项”(物理地址)映射表的“表索引”(虚拟地址,以 M 字节划分)
0x3000x3000_00000xc00 (M)
0x3010x3010_00000xc01 (M)
0x3020x3020_00000xc02 (M)
0x3030x3030_00000xc03 (M)
… (M)
0x3FF0x3FF0_00000xcFF (M)

虚拟地址范围 0xc000_0000 ~ 0xcFFF_FFFF,将其映射到物理地址 0x3000_0000 ~ 0x3FFF_FFFF 。

如下图可以看到,物理地址 0x3000_0000 ~ 0x3FFF_FFFF 是 uboot 设置的 DMC0 区域。

在这里插入图片描述

在这里插入图片描述


9.

在这里插入图片描述

base 的取值映射表的“表项”(物理地址)映射表的“表索引”(虚拟地址,以 M 字节划分)
0xd000xd000_00000xd00 (M)
0xd010xd010_00000xd01 (M)
0xd020xd020_00000xd02 (M)
0xd030xd030_00000xd03 (M)
… (M)
0xFFF0xFFF0_00000xFFF (M)

虚拟地址范围 0xd000_0000 ~ 0xFFFF_FFFF,将其映射到物理地址 0xd000_0000 ~ 0xFFFF_FFFF 。

如下图可以看到,物理地址 0xd000_0000 ~ 0xFFFF_FFFF 代表的区域。
在这里插入图片描述


总结

VA					PA					length
0-10000000			0-100'			    256MB
10000000-20000000	0					256MB
20000000-60000000	20000000-60000000	1GB		512-1.5G
60000000-80000000	0					512MB	1.5G-2G
80000000-b0000000	80000000-b0000000	768MB	2G-2.75G
b0000000-c0000000	b0000000-c0000000	256MB	2.75G-3G
c0000000-d0000000	30000000-40000000	256MB	3G-3.25G
d-完				d-完				768MB	3.25G-4G

DRAM 的有效范围:
DMC0: 0x30000000 ~ 0x3FFFFFFF
DMC1: 0x40000000 ~ 0x4FFFFFFF

结论:虚拟地址映射只是把虚拟地址的 c0000000 开头的 256MB ,映射到了 DMC0 的 30000000 开头的 256MB 物理内存上去了。其他的虚拟地址空间根本没动,还是原样映射的。

思考:为什么配置时将链接地址设置为 c3e00000,因为这个地址将来会被映射到33e00000 这个物理地址。


六、start.S 解析11

1、再次设置栈

在这里插入图片描述

(1) 第三次设置栈。这次设置栈还是在 DDR 中,之前虽然已经在 DDR 中设置过一次栈了,但是本次设置栈的目的,是将栈放在比较合适(安全,紧凑而不浪费内存)的地方。

(2) 我们实际将栈设置在 uboot 起始地址上方 2MB 处,这样安全的栈空间是:2MB-uboot大小-0x1000= 1.8MB 左右。这个空间既没有太浪费内存,又足够安全。


2、清理bss

在这里插入图片描述

(1) 清理 bss 段代码和裸机中讲的一样。注意表示 bss 段的开头和结尾地址的符号是从链接脚本 u-boot.lds 得来的。


3、ldr pc, _start_armboot

在这里插入图片描述

(1) start_armbootuboot/lib_arm/board.c 中,这是一个 C 语言实现的函数。这个函数就是 uboot 的第二阶段

这句代码的作用,就是将 uboot 第二阶段执行的函数的地址传给 pc。实际上就是使用一个远跳转,直接跳转到 DDR 中的第二阶段开始地址处

(2) 远跳转的含义就是,这句语句加载的地址和当前运行地址无关,而和链接地址有关。因此这个远跳转可以实现,从 SRAM 中的第一阶段跳转到 DDR 中的第二阶段

(3) 这里这个远跳转 ldr pc, _start_armboot,就是 uboot 的第一阶段和第二阶段的分界线


4、总结:uboot的第一阶段做了哪些工作

(1) 构建异常向量表;
(2) 设置 CPU 为 SVC 模式;
(3) 关看门狗;
(4) 开发板供电置锁;
(5) 时钟初始化;
(6) DDR 初始化;
(7) 串口初始化并打印"OK";
(8) uboot 工程的重定位;
(9) 建立映射表并开启 MMU;
(10) 跳转到第二阶段(BL2);


三次设置 sp 栈指针

  • 第一次:因为 DDR 尚未初始化,因此程序执行都是在 SRAM 中,所以在 SRAM 中分配了一部分内存作为栈。

  • 第二次:因为 DDR 已经被初始化了,因此要把栈挪移到 DDR 中,所以要重新设置栈(start.S 297-299 行);这里实际设置的栈的地址是 33E00000,刚好在 uboot 的代码段的下面紧挨着。

    为什么要再次设置栈?因为 DDR 已经初始化了,已经有大片内存可以用了,没必要再把栈放在 SRAM 中可怜兮兮的了;原来 SRAM 中内存大小空间有限,栈放在那里要注意不能使用过多的栈,否则栈会溢出,我们及时将栈迁移到 DDR 中,也是为了尽可能避免栈使用时候的小心翼翼。

  • 第三次:这次设置栈还是在 DDR 中,之前虽然已经在 DDR 中设置过一次栈了,但是本次设置栈的目的,是将栈放在比较合适(安全,紧凑而不浪费内存)的地方。

    我们实际 将栈设置在 uboot 起始地址上方 2MB 处,这样安全的栈空间是:2MB-uboot大小-0x1000= 1.8MB 左右。这个空间既没有太浪费内存,又足够安全。


源自朱有鹏老师.

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

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

相关文章

计算机网络1:Tcp三次握手和四次挥手

一、TCP传输的过程-三次握手 1.建立连接并确认连接&#xff08;三次握手&#xff09; ** 过程&#xff1a; ** &#xff08;1&#xff09;客户端向服务端发出连接请求SYN1&#xff0c;seqx&#xff0c;等待服务端响应.状态由CLOSED转为SYN_SENT &#xff08;2&#xff09;服务…

升级到https

现在很多站长都会考虑将自己的站点从http升级到https&#xff0c;不仅是基于安全的考虑&#xff0c;有的也是因为第三方平台的限制&#xff0c;如谷歌浏览器会将http站点标记为不安全的站点&#xff0c;微信平台要求接入的微信小程序必须使用https等。 那如何将一个http站点升…

C++006-C++分支结构练习题

文章目录C006-C分支结构练习题案例练习题目描述 有一门课不及格的学生题目描述 分段函数题目描述 骑车与走路在线练习&#xff1a;总结C006-C分支结构练习题 在线练习&#xff1a; http://noi.openjudge.cn/ch0104/ https://www.luogu.com.cn/ 案例练习 参考&#xff1a;http…

春招Leetcode刷题日记-D1-贪心算法-分配问题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 D1-贪心算法-分配问题何为贪心力扣455. 分发饼干思路代码何为贪心 1、顾名思义&#xff0c;贪心算法采用贪心的策略&#xff0c;保证每次操作都是局部最优的&#xff0c;从而…

神经网络损失函数分布可视化神器

论文名称和地址&#xff1a;Visualizing the Loss Landscape of Neural Netshttps://arxiv.org/pdf/1712.09913.pdf1.1 背景和动机作者主要想研究几个问题&#xff1a;为什么我们能够最小化高度非凸神经损失函数&#xff1f;为什么得到的最小值这个结果具有泛化性&#xff1f;不…

【C语言进阶】预处理与程序环境

目录一.详解编译与链接1.前言2.翻译环境3.剖析编译过程4.运行环境二.预处理详解1.预定义符号2.剖析#define(1).定义标识符(2).定义宏(3).替换规则(4).#和##(5).宏与函数的对比(6).#undef3.条件编译4.文件包含(1).头文件包含的方式(2).嵌套文件包含一.详解编译与链接 1.前言 在…

《流浪地球2》的现实倒影(三):从脑机接口到数字永生

是人&#xff0c;就会死。这个事实听起来或许很悲哀&#xff0c;但电影《流浪地球2》在一开始&#xff0c;就给出了另一种可能性——疯狂科学家进行数字生命实验&#xff0c;通过连接大脑的电极片&#xff0c;将思维意识上传到计算机&#xff0c;从而让人永生。电影开头的这位印…

《Keras深度学习:入门、实战与进阶》CIFAR-10图像识别

本文摘自《Keras深度学习&#xff1a;入门、实战与进阶》。 https://item.jd.com/10038325202263.html 这个数据集由Alex Krizhevsky、Vinod Nair和Geoffrey Hinton收集整理&#xff0c;共包含了60000张3232的彩色图像&#xff0c;50000张用于训练模型、10000张用于评估模型。…

JUC并发编程学习笔记(一)——知识补充(Threadlocal和引用类型)

强引用、弱引用、软引用、虚引用 Java执行 GC(垃圾回收)判断对象是否存活有两种方式&#xff0c;分别是引用计数法和引用链法(可达性分析法)。 **引用计数&#xff1a;**Java堆中给每个对象都有一个引用计数器&#xff0c;每当某个对象在其它地方被引用时&#xff0c;该对象的…

文献阅读:Scaling Instruction-Finetuned Language Models

文献阅读&#xff1a;Scaling Instruction-Finetuned Language Models 1. 文章简介2. 实验 1. 数据集 & 模型 1. 数据集考察2. 使用模型 2. scale up对模型效果的影响3. CoT对模型效果的影响4. 不同模型下Flan的影响5. 开放接口人工标注指标 3. 结论 文献链接&#xff1a;…

【C++】类和对象(一)

目录一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装4.1、访问限定符4.2、封装五、类的作用域六、类的实例化七、类对象的大小八、this指针8.1、this指针的引出8.2、this指针的特性8.3、C语言和C实现Stack的对比一、面向过程和面向对象初步认…

XSS漏洞,通过XSS实现网页挂马

**今天讲下通过XSS实现网页挂马~*&#xff0c;目的是了解安全方面知识&#xff0c;提升生活网络中辨别度 原理&#xff1a; 实验分为两部分&#xff1a; 1、通过Kali linux&#xff0c;利用MS14_064漏洞&#xff0c;制作一个木马服务器。存在该漏洞的用户一旦通过浏览器访问木…

C语言(C文件处理函数和文件指针)

C语言有很多文件操作函数&#xff0c;这里我们挑了一些重要的开始讲&#xff0c;首先说下这些函数都定义在stdio.h头文件中 目录 一.文件指针 二.文件处理函数 1.fopen&#xff08;打开文件&#xff09; 2.fclose(关闭文件) 3.getc和putc(从文件指针读取字符) 4.I/O工作…

「C++控制台生存游戏」暗黑体素 DarkVoxel 控制台版

“《只有作者能看懂的一款游戏》” 刚进高中前开始写的一款抽象的生存游戏 BUG很多请见谅 ###【点击此处&#xff0c;免费畅玩】### 类似泰拉瑞亚的一款游戏 『暗黑体素 DarkVoxel』 直接上图&#xff01; 用控制台写出如此奇葩的生存游戏&#xff0c;可谓世间少有。 操作…

2022黑马Redis跟学笔记.实战篇(二)

2022黑马Redis跟学笔记.实战篇 二实战篇Redis开篇导读4.1短信登录4.1.1. 搭建黑马点评项目一、导入黑马点评项目二、导入SQL三、有关当前模型四、导入后端项目相关依赖配置redis和mysql连接项目组成概述关闭Linux防火墙五、导入前端工程六、 运行前端项目4.1.2. 基于Session实现…

选购交换机的参数依据和主要的参数指标详解

如何选购交换机&#xff1f;用什么交换机&#xff1f;在选购交换机时交换机的优劣无疑十分的重要&#xff0c;而交换机的优劣要从总体构架、性能和功能三方面入手。交换机选购时。性能方面除了要满足RFC2544建议的基本标准&#xff0c;即吞吐量、时延、丢包率外&#xff0c;随着…

网络是怎么连接笔记(一)WEB浏览器

文章目录介绍生成HTTP请求消息向DNS服务器查询WEB服务的IP地址全世界DNS服务器的大接力委托协议栈发送消息介绍 互联网整个消息传递流程 生成HTTP请求消息向DNS服务器查询WEB服务的IP地址然后DNS服务器进行查询IP地址委托协议给对应IP发送消息 生成HTTP请求消息 整个网络发…

Spring面试重点(三)——AOP循环依赖

Spring面试重点 AOP 前置通知&#xff08;Before&#xff09;&#xff1a;在⽬标⽅法运行之前运行&#xff1b;后置通知&#xff08;After&#xff09;&#xff1a;在⽬标⽅法运行结束之后运行&#xff1b;返回通知&#xff08;AfterReturning&#xff09;&#xff1a;在⽬标…

2023年前端面试知识点总结(CSS篇)

近期整理了一下高频的前端面试题&#xff0c;分享给大家一起来学习。如有问题&#xff0c;欢迎指正&#xff01; 1. 对CSS盒模型的理解 CSS3的盒模型有两种盒子模型&#xff1a;标准盒子模型、IE盒子模型 盒模型都是由四个部分组成的&#xff0c;分别是content&#xff08;内容…

layui框架学习(6:基础菜单)

菜单是应用系统的必备元素&#xff0c;虽然网页中的导航也能作为菜单使用&#xff0c;但菜单和导航的样式和用途有所不同&#xff08;不同之处详见参考文献5&#xff09;。Layui中用不同的预设类定义菜单和导航的样式&#xff0c;同时二者依赖的模块也不一样。本文主要学习和记…