Linux ARM64架构 动态替换 altinstructions
文章目录
- 简介
- 一、altinstructions节
- 1.1 .altinstructions
- 1.2 .rela.altinstructions
- 二、内核模块重定位源码分析
- 参考资料
简介
在内核开发中,有时需要对内核代码进行修补,以解决bug、优化性能或引入新功能。替代指令(altinstructions)提供了一种在不修改原始代码的情况下进行修补的方法。它允许开发者在原始指令的位置插入替代指令,以实现所需的功能变更。
内核版本:4.19.90
处理器架构:aarch64
以vfat.ko模块为例:
# readelf -S vfat.ko
There are 35 section headers, starting at offset 0x6c08:节头:[号] 名称 类型 地址 偏移量大小 全体大小 旗标 链接 信息 对齐......[10] .altinstructions PROGBITS 0000000000000000 000037680000000000000078 0000000000000000 A 0 0 1[11] .rela.altinstruct RELA 0000000000000000 000037e000000000000001e0 0000000000000018 I 31 10 8......
我目前这台机器arm64 架构的OS的内核模块没有 .altinstr_replacement 节(还是arm64 架构的 Linux 都没有.altinstr_replacement 节,这点有待确定)。
一、altinstructions节
1.1 .altinstructions
.altinstructions 是 Linux 内核中的一个特殊节(section),用于定义指令替换规则。它允许内核在运行时替换特定的汇编指令序列,以提高性能或解决特定的问题。
指令替换的规则包括两个部分:原始指令序列和替换指令序列。内核在执行时会检查原始指令序列是否匹配,如果匹配则使用替换指令序列来取代它。
.altinstructions 节主要用于在 Linux 内核中进行指令替换或修补。它提供了在运行时替换特定指令序列的机制,常用于优化关键代码路径或解决硬件问题。
struct alt_instr {s32 orig_offset; /* offset to original instruction */s32 alt_offset; /* offset to replacement instruction */u16 cpufeature; /* cpufeature bit set for replacement */u8 orig_len; /* size of original instruction(s) */u8 alt_len; /* size of new instruction(s), <= orig_len */
};
(1)orig_offset(s32类型):原始指令的偏移量。指示原始指令在代码段中的位置。
(2)alt_offset(s32类型):替换指令的偏移量。指示替换指令在代码段中的位置。
(3)cpufeature(u16类型):替换指令所需的CPU特性位。这个字段用于在替换指令被应用时检查CPU是否支持相应的特性。
(4)orig_len(u8类型):原始指令的长度。表示原始指令所占用的字节数。
(5)alt_len(u8类型):新指令的长度。表示替换指令所占用的字节数。这个值必须小于等于 orig_len,以确保替换后的指令不会超出原始指令的范围。
.altinstructions 节中保存了 struct alt_instr 结构体数组。数组中的每一个元素代表了一条替换指令记录,给出了原始指令的位置、长度和用于修补原始指令的新指令的位置、长度。
这个结构体用于在 Linux 内核的 .altinstructions 节中定义指令替换规则。每个结构体实例表示一条指令的替换规则,其中包含原始指令和替换指令的相关信息。通过使用这些结构体,内核可以在运行时根据需要进行指令替换,以优化性能或解决特定的硬件问题。
# readelf -x 10 vfat.ko“.altinstructions”节的十六进制输出:NOTE: This section has relocations against it, but these have NOT been applied to this dump.0x00000000 00000000 00000000 05000c0c 00000000 ................0x00000010 00000000 05000c0c 00000000 00000000 ................0x00000020 05000c0c 00000000 00000000 05000c0c ................0x00000030 00000000 00000000 05000c0c 00000000 ................0x00000040 00000000 05000c0c 00000000 00000000 ................0x00000050 05000c0c 00000000 00000000 05000c0c ................0x00000060 00000000 00000000 05000c0c 00000000 ................0x00000070 00000000 05000c0c ........
struct alt_instr {s32 orig_offset; /* offset to original instruction */s32 alt_offset; /* offset to replacement instruction */u16 cpufeature; /* cpufeature bit set for replacement */u8 orig_len; /* size of original instruction(s) */u8 alt_len; /* size of new instruction(s), <= orig_len */
};
sizeof(struct alt_instr) = 12
“.altinstructions”节 都是存放struct alt_instr结构体数据
因此这个节存放了 10 个struct alt_instr结构体。
1.2 .rela.altinstructions
.rela.altinstructions节是一个重定位节,用于存储.altinstructions节中数据结构的重定位信息。
在Linux ELF(Executable and Linkable Format)文件中,重定位节(Relocation Section)是用于存储链接器在链接过程中需要进行地址修正的信息。重定位节包含了需要修改的符号引用和相关的重定位类型。
重定位节中都是未定义的符号,即不是本模块定义的符号,因此这些符号的地址在内核模块加载时需要进行重新处理。
重定位节的名称通常以 “.rel” 或 “.rela” 开头,后面跟随符号表中相关的节名称。例如,“.rel.text” 表示与代码段(.text)相关的重定位信息。
在链接过程中,链接器会根据符号引用和重定位类型,将重定位节中的每个重定位项应用于对应的位置,修正地址或符号引用。
重定位节的结构和格式可以因不同的体系结构和文件格式而有所不同,但通常包含以下信息:
(1)Offset(偏移量):指定需要修正的位置在节中的偏移量。
(2)Symbol Index(符号索引):指定需要修正的符号引用在符号表中的索引。
(3)Type(类型):指定重定位的类型,如绝对重定位、PC相对重定位等。
(4)Addend(增量):一些重定位类型需要额外的增量值,用于计算最终的修正值。
/* Relocation table entry with addend (in section of type SHT_RELA). */typedef struct
{Elf64_Addr r_offset; /* Address */Elf64_Xword r_info; /* Relocation type and symbol index */Elf64_Sxword r_addend; /* Addend */
} Elf64_Rela;
sizeof(Elf64_Rela) = 24
# readelf -x 11 vfat.ko“.rela.altinstructions”节的十六进制输出:0x00000000 00000000 00000000 05010000 02000000 ................0x00000010 e0040000 00000000 04000000 00000000 ................0x00000020 05010000 02000000 28210000 00000000 ........(!......0x00000030 0c000000 00000000 05010000 02000000 ................0x00000040 5c070000 00000000 10000000 00000000 \...............0x00000050 05010000 02000000 34210000 00000000 ........4!......0x00000060 18000000 00000000 05010000 02000000 ................0x00000070 54080000 00000000 1c000000 00000000 T...............0x00000080 05010000 02000000 40210000 00000000 ........@!......0x00000090 24000000 00000000 05010000 02000000 $...............0x000000a0 24090000 00000000 28000000 00000000 $.......(.......0x000000b0 05010000 02000000 4c210000 00000000 ........L!......0x000000c0 30000000 00000000 05010000 02000000 0...............0x000000d0 f41a0000 00000000 34000000 00000000 ........4.......0x000000e0 05010000 02000000 58210000 00000000 ........X!......0x000000f0 3c000000 00000000 05010000 02000000 <...............0x00000100 b41c0000 00000000 40000000 00000000 ........@.......0x00000110 05010000 02000000 64210000 00000000 ........d!......0x00000120 48000000 00000000 05010000 02000000 H...............0x00000130 e01e0000 00000000 4c000000 00000000 ........L.......0x00000140 05010000 02000000 70210000 00000000 ........p!......0x00000150 54000000 00000000 05010000 02000000 T...............0x00000160 341f0000 00000000 58000000 00000000 4.......X.......0x00000170 05010000 02000000 7c210000 00000000 ........|!......0x00000180 60000000 00000000 05010000 02000000 `...............0x00000190 28200000 00000000 64000000 00000000 ( ......d.......0x000001a0 05010000 02000000 88210000 00000000 .........!......0x000001b0 6c000000 00000000 05010000 02000000 l...............0x000001c0 84200000 00000000 70000000 00000000 . ......p.......0x000001d0 05010000 02000000 94210000 00000000 .........!......
计算得到该重定位节中有20个Elf64_Rela结构体数据。
# readelf -r vfat.ko | grep -A 25 .rela.altinstructions
重定位节 '.rela.altinstructions' at offset 0x37e0 contains 20 entries:偏移量 信息 类型 符号值 符号名称 + 加数
000000000000 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 4e0
000000000004 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 2128
00000000000c 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 75c
000000000010 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 2134
000000000018 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 854
00000000001c 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 2140
000000000024 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 924
000000000028 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 214c
000000000030 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 1af4
000000000034 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 2158
00000000003c 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 1cb4
000000000040 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 2164
000000000048 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 1ee0
00000000004c 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 2170
000000000054 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 1f34
000000000058 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 217c
000000000060 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 2028
000000000064 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 2188
00000000006c 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 2084
000000000070 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 2194
其中.text + 4e0、.text + 75、.text + 854等都是对应的 BL 函数跳转指令:
这里的__ll_sc___cmpxchg_case_acq_4函数和__ll_sc___cmpxchg_case_mb_8不属于vfat.ko内核模块中的函数,因此需要重定位来获取对应函数的位置。
# cat /proc/kallsyms | grep '\<__ll_sc___cmpxchg_case_acq_4\>'
ffff3c3a3fa01bf0 T __ll_sc___cmpxchg_case_acq_4
# cat /proc/kallsyms | grep '\<__ll_sc___cmpxchg_case_mb_8\>'
ffff3c3a3fa01d28 T __ll_sc___cmpxchg_case_mb_8
可以看到这两个函数都属于内核镜像中定义的函数。
aarch64一条指令四个字节,bl是函数调用指令,比如一个内核模块调用内核镜像或者其他模块的函数:
vfat.ko内核模块中函数调用内核的函数kmem_cache_alloc_trace:
94000000 bl 0 <kmem_cache_alloc_trace>
94:1001 0100
上面提到.altinstructions有10 个struct alt_instr结构体,.rela.altinstructions节中有20个Elf64_Rela结构体数据。
其中.text + 2128、.text + 2134、.text + 2140等对应的指令如下所示:
这10个重定位项都是在 .text 代码段的末尾,对应的指令都是:
MOV X30, X1
对于 x30 寄存器:
在ARM64体系结构中,寄存器 x30 是通用寄存器之一,也称为"General Purpose Register"。ARM64体系结构共有31个通用寄存器,编号从x0到x30。
寄存器 x30 在ARM64体系结构中有一个特殊的角色,它被称为"链接寄存器"(Link Register),也经常以 “lr” 的缩写表示。链接寄存器用于存储函数的返回地址,在函数调用过程中起到重要的作用。
当一个函数被调用时,当前函数的返回地址(即调用该函数的指令的下一条指令的地址)会被保存在链接寄存器 x30 中。函数执行完毕后,通过将链接寄存器中的返回地址装载到程序计数器(PC)中,控制流程可以返回到调用函数的位置。
链接寄存器 x30 还可以在函数中用作通用寄存器,存储临时数据、地址计算和数据传输等。但需要注意的是,一旦在函数中使用链接寄存器存储其他数据,必须在函数返回之前将其恢复为正确的返回地址,以确保函数返回到正确的位置。
因此我们可以知道 .altinstructions 节中有10 个struct alt_instr结构体,也就是10处指令要替换,且都是BL函数调用替换,因此会有相应的 RET 函数返回,因此.rela.altinstructions节中有20个Elf64_Rela结构体数据。每一个 .altinstructions 节中的struct alt_instr结构体对应一个 BL和一个RET。
二、内核模块重定位源码分析
// linux-4.19.90/kernel/module.cSYSCALL_DEFINE3(init_module......)-->load_module()-->post_relocation()/* Arch-specific module finalizing. */-->module_finalize()
其中module_finalize是一个与体系架构有关的函数,这里我们主要关注 aach64位架构:
typedef struct elf64_shdr {Elf64_Word sh_name; /* Section name, index in string tbl */Elf64_Word sh_type; /* Type of section */Elf64_Xword sh_flags; /* Miscellaneous section attributes */Elf64_Addr sh_addr; /* Section virtual addr at execution */Elf64_Off sh_offset; /* Section file offset */Elf64_Xword sh_size; /* Size of section in bytes */Elf64_Word sh_link; /* Index of another section */Elf64_Word sh_info; /* Additional section information */Elf64_Xword sh_addralign; /* Section alignment */Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
// linux-4.19.90/arch/arm64/kernel/module.cint module_finalize(const Elf_Ehdr *hdr,const Elf_Shdr *sechdrs,struct module *me)
{const Elf_Shdr *s, *se;const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {if (strcmp(".altinstructions", secstrs + s->sh_name) == 0)apply_alternatives_module((void *)s->sh_addr, s->sh_size);}return 0;
}
// linux-4.19.90/arch/arm64/kernel/alternative.cvoid apply_alternatives_module(void *start, size_t length)
{struct alt_region region = {.begin = start,.end = start + length,};__apply_alternatives(®ion, true);
}
struct alt_instr {s32 orig_offset; /* offset to original instruction */s32 alt_offset; /* offset to replacement instruction */u16 cpufeature; /* cpufeature bit set for replacement */u8 orig_len; /* size of original instruction(s) */u8 alt_len; /* size of new instruction(s), <= orig_len */
};struct alt_region {struct alt_instr *begin;struct alt_instr *end;
};typedef void (*alternative_cb_t)(struct alt_instr *alt,__le32 *origptr, __le32 *updptr, int nr_inst);static void __apply_alternatives(void *alt_region, bool is_module)
{struct alt_instr *alt;struct alt_region *region = alt_region;__le32 *origptr, *updptr;alternative_cb_t alt_cb;for (alt = region->begin; alt < region->end; alt++) {int nr_inst;/* Use ARM64_CB_PATCH as an unconditional patch */if (alt->cpufeature < ARM64_CB_PATCH &&!cpus_have_cap(alt->cpufeature))continue;if (alt->cpufeature == ARM64_CB_PATCH)BUG_ON(alt->alt_len != 0);elseBUG_ON(alt->alt_len != alt->orig_len);pr_info_once("patching kernel code\n");origptr = ALT_ORIG_PTR(alt);updptr = is_module ? origptr : lm_alias(origptr);nr_inst = alt->orig_len / AARCH64_INSN_SIZE;if (alt->cpufeature < ARM64_CB_PATCH)alt_cb = patch_alternative;elsealt_cb = ALT_REPL_PTR(alt);alt_cb(alt, origptr, updptr, nr_inst);......}......}
函数的参数 alt_region 是一个指向替代指令区域的指针,is_module 是一个布尔值,表示是否为模块代码,这里传入的是 true ,表示是模块代码。
函数通过循环遍历 alt_region (.altinstructions)中的每个替代指令,每个替代指令存储在结构体 alt_instr 中,包含原始指令和替代指令的信息。
函数首先检查替代指令的 cpufeature 字段。如果该字段小于 ARM64_CB_PATCH 并且当前 CPU 不支持该特性,则跳过该替代指令。
如果替代指令的 cpufeature 等于 ARM64_CB_PATCH,则需要确保 alt_len(替代指令长度)为零。否则,需要确保 alt_len 和 orig_len(原始指令长度)相等。如果上述条件不满足,则会触发错误(使用 BUG_ON)。
在确定替代指令有效后,函数使用 pr_info_once 记录一条消息,指示正在对内核代码进行修补。
根据 is_module 的值,函数设置 origptr 和 updptr 变量。如果是模块代码,则 origptr 指向原始指令,否则通过 lm_alias 函数获取一个别名。这里是模块代码,origptr 指向原始指令。
通过将替代指令的长度 alt->orig_len 除以 ARM64 指令的大小 AARCH64_INSN_SIZE,计算出指令的数量 nr_inst。
/* A64 instructions are always 32 bits. */
#define AARCH64_INSN_SIZE 4
根据替代指令的 cpufeature 值,选择相应的回调函数 alt_cb。如果 cpufeature 小于 ARM64_CB_PATCH,则选择 patch_alternative 函数作为回调函数;否则使用 ALT_REPL_PTR(alt) 来确定回调函数。
调用回调函数 alt_cb,并将 alt、origptr、updptr 和 nr_inst 作为参数,来应用替代指令。
这段代码目的是应用替代指令(alternative instructions),用新的指令替换原始指令,根据替代指令的条件和特性选择性地应用替代。它通过调用相应的回调函数来执行替代指令操作。从而修复或改进内核的行为。
参考资料
Linux 4.19.90
相关文章:

Linux ARM64架构 动态替换 altinstructions
文章目录 简介一、altinstructions节1.1 .altinstructions1.2 .rela.altinstructions 二、内核模块重定位源码分析参考资料 简介 在内核开发中,有时需要对内核代码进行修补,以解决bug、优化性能或引入新功能。替代指令(altinstructions&…...

Mac显示隐藏文件夹
1、设置隐藏文件可见 defaults write com.apple.finder AppleShowAllFiles TRUE 2、killall Finder killall Finder...
使用 Habana Gaudi2 加速视觉语言模型 BridgeTower
🤗 宝子们可以戳 阅读原文 查看文中所有的外部链接哟! 在对最先进的视觉语言模型 BridgeTower 进行微调时,使用 Optimum Habana v1.6, Habana Gaudi2 可以达到 近 3 倍于 A100 的速度。硬件加速的数据加载以及 fast DDP 这两个新特…...

mysql查询语句之实践篇
基础查询语句 完整语法格式如下: select 字段列表 from 表名列表 where 条件列表 group by 分组字段 having 分组之后的条件 order by 排序 limit 分页限定 -- 创建表 create table stu(id int,name varchar(20),chinese double,english double,math double ); --…...
Linux 和 MacOS 中的 profile 文件详解(二)
上篇文章讲解了 profile 文件的作用、login shell 和 non-login shell 的定义、不同 profile 被 bash shell 在不同情况下的加载顺序和作用,本文讲解一下 zsh shell 相关的知识。 zsh shell MacOS 从 Catalina 版本开始将 zsh 作为默认登录 shell 和交互式 shell。…...

Python之多重继承
一、多重继承 Python支持多重继承,一个子类可以有多个“直接父类”。这样,就具备了“多个父类”的特点。但是由于,这样会被“类的整体层次”搞的异常复杂,尽量避免使用。 class A:def aa(self):print("aa") class B…...

前端CSS文字阴影text-shadow记录
前端CSS文字阴影text-shadow记录 一、文字阴影 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Doc…...

maven 删除下载失败的包
本文介绍了当Maven包报红时,使用删除相关文件的方法来解决该问题。文章详细说明了_remote.repositories、.lastUpdated和_maven.repositories文件的作用,以及如何使用命令行删除这些文件。这些方法可以帮助开发者解决Maven包报红的问题,确保项…...

《吐血整理》高级系列教程-吃透Fiddler抓包教程(37)-掌握Fiddler中Fiddler Script用法你有多牛逼-下
1.简介 Fiddler是一款强大的HTTP抓包工具,它能记录所有客户端和服务器的http和https请求,允许你监视,设置断点,甚至修改输入输出数据. 使用Fiddler无论对开发还是测试来说,都有很大的帮助。Fiddler提供的功能基本上能…...

网络安全进阶学习第十二课——SQL手工注入3(Access数据库)
文章目录 注入流程:1、判断数据库类型2、判断表名3、判断列名4、判断列数1)判断显示位 5、判断数据长度6、爆破数据内容 注入流程: 判断数据库类型 ——> 判断表名 ——> 判断列名 ——> 判断列名长度 ——> 查出数据。 asp的网…...
Zookeeper集群+Kafka集群
目录 一丶Zookkeeper概述 二、Zookeeper 特点 2.1Zookeeper 应用场景 2.2Zookeeper 选举机制 2.2.1第一次启动选举机制 2.2.2非第一次启动选举机制 三、部署 Zookeeper 集群 3.1//安装 JDK 3.2安装 Zookeeper 3.2.1修改配置文件 3.2.2拷贝配置好的 Zookeeper 配置文件…...

管理类联考——逻辑——论证逻辑——汇总篇——目录+提炼
文章目录 一、削弱方法关系的削弱必要方法的削弱因果推理的削弱果因推理的削弱概念跳跃的削弱数量比例的削弱比例因果的削弱 二、支持方法关系的支持必要方法的支持因果推理的支持果因推理的支持概念跳跃的支持数量比例的支持比例因果的支持 三、假设方法关系的假设必要方法的假…...

用excel格式书写的接口用例执行脚本
创建测试用例和测试结果集文件夹: excel编写的接口测试用例如下: 1 encoding 响应的编码格式。所测项目大部分是utf-8,有一个特殊项目是utf-8-sig 2 params 对应requests的params 3 data,对应requests的data 有些参数是动态的&a…...

【flink】Chunk splitting has encountered exception
执行任务报错: Chunk splitting has encountered exception 错误信息截图: 完整的错误信息: 16:30:43,911 ERROR org.apache.flink.runtime.source.coordinator.SourceCoordinator [SourceCoordinator-Source: CDC Sourceorg.jobslink.flink…...

单元测试用例分组 demo
文章目录 目标1、使用 Category 进行用例分组(1)设置用例组(2)编写测试类,case设置对应的用例组(3)编写执行类(4)查看运行结果(5)联系项目 2、参数…...

观察者模式(Observer)
观察着模式是一种行为设计模式,可以用来定义对象间的一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。 观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图…...

20天学会rust(二)rust的基础语法篇
在第一节(20天学rust(一)和rust say hi)我们配置好了rust的环境,并且运行了一个简单的demo——practice-01,接下来我们将从示例入手,学习rust的基础语法。 首先来看下项目结构: 项目…...

Stephen Wolfram:嵌入的概念
The Concept of Embeddings 嵌入的概念 Neural nets—at least as they’re currently set up—are fundamentally based on numbers. So if we’re going to to use them to work on something like text we’ll need a way to represent our text with numbers. And certain…...
springboot,swagger多个mapper包,多个controller加载问题
启动类添加MapperScan({"xxx.xxx.xxx.mapper","xxx.xxx.xxx.mapper"}) swagger配置类添加 Bean public Docket api01() {return new Docket(DocumentationType.SWAGGER_2)//.enable(swagger_is_enabl).apiInfo(new ApiInfoBuilder().title("你的title…...
湖大CG满分教程:作业训练四编程题20. 回文串(暴力×动态规划算法√)
问题描述 “回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。给你一个字符串,问最少在字符串尾添加多少字符,可以使得字符串变为回文串。 输入格式 有多组测试数据。 每组测试数据第一行是一个正整数N…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...