Linux 内核连接脚本vmlinux.lds.S

2023-11-03 22:44

本文主要是介绍Linux 内核连接脚本vmlinux.lds.S,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

源码基于:Linux5.4

0. 前言

现代软件工程中,一个大的工程通常都会有多个源文件组成,其中包括高级计算机语言编写的源文件,以及汇编语言编写的汇编文件。在编译构建过程中会分别对这些源文件进行汇编、编译生成目标文件,这些目标文件包含:代码段、数据段、符号表等内容。链接器主要任务是将符号引用解析到符号定义上,将多个目标文件和库文件合并成为一个可执行文件或者动态链接库,生成符号表,并对程序代码做最后的检查和优化。

本文主要针对 ARM64架构的连接脚本 vmlinux.lds.S 进行剖析。

因为 vmlinux.lds.S 的内容比较多,本文将其拆分后分析。

1. vmlinux.lds.S 源码

arch/arm64/kernel/vmlinux.lds.S#include <asm-generic/vmlinux.lds.h>
#include <asm/cache.h>
#include <asm/kernel-pgtable.h>
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/page.h>
#include <asm/pgtable.h>#include "image.h"/* .exit.text needed in case of alternative patching */
#define ARM_EXIT_KEEP(x)	x
#define ARM_EXIT_DISCARD(x)OUTPUT_ARCH(aarch64)
ENTRY(_text)jiffies = jiffies_64;#define HYPERVISOR_EXTABLE					\. = ALIGN(SZ_8);					\__start___kvm_ex_table = .;				\*(__kvm_ex_table)					\__stop___kvm_ex_table = .;#define HYPERVISOR_TEXT					\/*						\* Align to 4 KB so that			\* a) the HYP vector table is at its minimum	\*    alignment of 2048 bytes			\* b) the HYP init code will not cross a page	\*    boundary if its size does not exceed	\*    4 KB (see related ASSERT() below)		\*/						\. = ALIGN(SZ_4K);				\__hyp_idmap_text_start = .;			\*(.hyp.idmap.text)				\__hyp_idmap_text_end = .;			\__hyp_text_start = .;				\*(.hyp.text)					\HYPERVISOR_EXTABLE				\__hyp_text_end = .;#define IDMAP_TEXT					\. = ALIGN(SZ_4K);				\__idmap_text_start = .;				\*(.idmap.text)					\__idmap_text_end = .;#ifdef CONFIG_HIBERNATION
#define HIBERNATE_TEXT					\. = ALIGN(SZ_4K);				\__hibernate_exit_text_start = .;		\*(.hibernate_exit.text)				\__hibernate_exit_text_end = .;
#else
#define HIBERNATE_TEXT
#endif#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
#define TRAMP_TEXT					\. = ALIGN(PAGE_SIZE);				\__entry_tramp_text_start = .;			\*(.entry.tramp.text)				\. = ALIGN(PAGE_SIZE);				\__entry_tramp_text_end = .;
#else
#define TRAMP_TEXT
#endif/** The size of the PE/COFF section that covers the kernel image, which* runs from stext to _edata, must be a round multiple of the PE/COFF* FileAlignment, which we set to its minimum value of 0x200. 'stext'* itself is 4 KB aligned, so padding out _edata to a 0x200 aligned* boundary should be sufficient.*/
PECOFF_FILE_ALIGNMENT = 0x200;#ifdef CONFIG_EFI
#define PECOFF_EDATA_PADDING	\.pecoff_edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGNMENT); }
#else
#define PECOFF_EDATA_PADDING
#endifSECTIONS
{/** XXX: The linker does not define how output sections are* assigned to input sections when there are multiple statements* matching the same input section name.  There is no documented* order of matching.*//DISCARD/ : {ARM_EXIT_DISCARD(EXIT_TEXT)ARM_EXIT_DISCARD(EXIT_DATA)EXIT_CALL*(.discard)*(.discard.*)*(.interp .dynamic)*(.dynsym .dynstr .hash .gnu.hash)*(.eh_frame)}. = KIMAGE_VADDR + TEXT_OFFSET;.head.text : {_text = .;HEAD_TEXT}.text : {			/* Real text segment		*/_stext = .;		/* Text and read-only data	*/__exception_text_start = .;*(.exception.text)__exception_text_end = .;IRQENTRY_TEXTSOFTIRQENTRY_TEXTENTRY_TEXTTEXT_TEXTSCHED_TEXTCPUIDLE_TEXTLOCK_TEXTKPROBES_TEXTHYPERVISOR_TEXTIDMAP_TEXTHIBERNATE_TEXTTRAMP_TEXT*(.fixup)*(.gnu.warning). = ALIGN(16);*(.got)			/* Global offset table		*/}. = ALIGN(SEGMENT_ALIGN);_etext = .;			/* End of text section */RO_DATA(PAGE_SIZE)		/* everything from this point to     */EXCEPTION_TABLE(8)		/* __init_begin will be marked RO NX */NOTES. = ALIGN(PAGE_SIZE);idmap_pg_dir = .;. += IDMAP_DIR_SIZE;idmap_pg_end = .;#ifdef CONFIG_UNMAP_KERNEL_AT_EL0tramp_pg_dir = .;. += PAGE_SIZE;
#endifreserved_pg_dir = .;. += PAGE_SIZE;swapper_pg_dir = .;. += PAGE_SIZE;. = ALIGN(SEGMENT_ALIGN);__init_begin = .;__inittext_begin = .;INIT_TEXT_SECTION(8)__exittext_begin = .;.exit.text : {ARM_EXIT_KEEP(EXIT_TEXT)}__exittext_end = .;. = ALIGN(4);.altinstructions : {__alt_instructions = .;*(.altinstructions)__alt_instructions_end = .;}.altinstr_replacement : {*(.altinstr_replacement)}. = ALIGN(PAGE_SIZE);__inittext_end = .;__initdata_begin = .;.init.data : {INIT_DATAINIT_SETUP(16)INIT_CALLSCON_INITCALLINIT_RAM_FS*(.init.rodata.* .init.bss)	/* from the EFI stub */}.exit.data : {ARM_EXIT_KEEP(EXIT_DATA)}PERCPU_SECTION(L1_CACHE_BYTES).rela.dyn : ALIGN(8) {*(.rela .rela*)}__rela_offset	= ABSOLUTE(ADDR(.rela.dyn) - KIMAGE_VADDR);__rela_size	= SIZEOF(.rela.dyn);#ifdef CONFIG_RELR.relr.dyn : ALIGN(8) {*(.relr.dyn)}__relr_offset	= ABSOLUTE(ADDR(.relr.dyn) - KIMAGE_VADDR);__relr_size	= SIZEOF(.relr.dyn);
#endif. = ALIGN(SEGMENT_ALIGN);__initdata_end = .;__init_end = .;_data = .;_sdata = .;RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_ALIGN)/** Data written with the MMU off but read with the MMU on requires* cache lines to be invalidated, discarding up to a Cache Writeback* Granule (CWG) of data from the cache. Keep the section that* requires this type of maintenance to be in its own Cache Writeback* Granule (CWG) area so the cache maintenance operations don't* interfere with adjacent data.*/.mmuoff.data.write : ALIGN(SZ_2K) {__mmuoff_data_start = .;*(.mmuoff.data.write)}. = ALIGN(SZ_2K);.mmuoff.data.read : {*(.mmuoff.data.read)__mmuoff_data_end = .;}PECOFF_EDATA_PADDING__pecoff_data_rawsize = ABSOLUTE(. - __initdata_begin);_edata = .;BSS_SECTION(0, 0, 0). = ALIGN(PAGE_SIZE);init_pg_dir = .;. += INIT_DIR_SIZE;init_pg_end = .;__pecoff_data_size = ABSOLUTE(. - __initdata_begin);_end = .;STABS_DEBUGHEAD_SYMBOLS
}#include "image-vars.h"/** The HYP init code and ID map text can't be longer than a page each,* and should not cross a page boundary.*/
ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,"HYP init code too big or misaligned")
ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,"ID map text too big or misaligned")
#ifdef CONFIG_HIBERNATION
ASSERT(__hibernate_exit_text_end - (__hibernate_exit_text_start & ~(SZ_4K - 1))<= SZ_4K, "Hibernate exit text too big or misaligned")
#endif
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) <= 3*PAGE_SIZE,"Entry trampoline text too big")
#endif
/** If padding is applied before .head.text, virt<->phys conversions will fail.*/
ASSERT(_text == (KIMAGE_VADDR + TEXT_OFFSET), "HEAD is misaligned")

1.1 头文件

#include <asm-generic/vmlinux.lds.h>
#include <asm/cache.h>
#include <asm/kernel-pgtable.h>
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/page.h>
#include <asm/pgtable.h>#include "image.h"

上面的头文件,大多会使用宏定义的方式编写特定段的描述内容,用于在 vmlinux.lds.S 文件中引用。

 

1.2 参数设置

//指定了链接之后输出文件的体系结构是 aarch64
OUTPUT_ARCH(aarch64)//指定程序的入口地址为 _text
ENTRY(_text)//Linux内核中定义了jiffies变量来记录从系统启动到当前时刻系统时钟所产生的tick数
//通常都设置为 jiffies_64
jiffies = jiffies_64;

ENTRY() 用以指定程序的入口地址,这里指定是 _text,其他方式:

  • 在GCC 工具链 LD 命令通过 '-e' 参数指定入口点;
  • 在连接脚本中通过 ENTRY() 命令设定入口点;
  • 通过特定符号(例如 start 符号) 设置入口点;
  • 如果存在 .text section , 使用.text section的第一字节的位置值;
  • 使用值0;

 

1.3 宏定义描述

2. SECTIONS

SECTIONS { } 是链接脚本语法中的关键命令,用以描述输出文件的内存布局。

SECTIONS 命令告诉链接文件如何把输入文件的段映射到输出文件的各个段中,如何将输入段整合为输出段,如何把输出段放入程序地址空间和进程地址空间中。

2.1 /DISCARD/ 段

这是一个特殊的输出段,被该段引用的任何输入段,将不会出现在输出文件中。

	/DISCARD/ : {ARM_EXIT_DISCARD(EXIT_TEXT)ARM_EXIT_DISCARD(EXIT_DATA)EXIT_CALL*(.discard)*(.discard.*)*(.interp .dynamic)*(.dynsym .dynstr .hash .gnu.hash)*(.eh_frame)}

2.2 _text 段

	. = KIMAGE_VADDR + TEXT_OFFSET;.head.text : {_text = .;HEAD_TEXT}

'.' 号是连接脚本中一个特殊的符号,用以表示当前位置计数器。

最开始将 KIMAGE_VADDR + TEXT_OFFSET 赋值给 '.' 意思是把代码段的地址设置给当前位置;

KIMAGE_VADDR 在 memory.h 中定义:

arch/arm64/include/asm/memory.h#define KIMAGE_VADDR		(MODULES_END)

TEXT_OFFSET 在Makefile 中定义:

arch/arm64/MakefileTEXT_OFFSET := 0x00080000

.head.text 表示输出段,对应的输入段位 HEAD_TEXT

include/asm-generic/vmlinux.lds.h#define HEAD_TEXT  KEEP(*(.head.text))

意思是将所有目标文件中的 .head.text 都放入 .head.text 输出段中。

其中 _text = .; 用以标识 _text 段的开始就是当前位置;

《fixmap详解》一文中,我们看到 KIMAGE_VADDR 是在0xFFFF FFC0 0000 0000 基础上偏移 256M,即KIMAGE_VADDR 的地址为 0xFFFF FFC0 1000 0000。如果加上 TEXT_OFFSET 之后就会得到 .head.text 所在段的地址 0xFFFF FFC0 1008 0000,我们通过 readelf -S vmlinux 来看下:

There are 52 section headers, starting at offset 0x1c82de30:Section Headers:[Nr] Name              Type             Address           OffsetSize              EntSize          Flags  Link  Info  Align[ 0]                   NULL             0000000000000000  000000000000000000000000  0000000000000000           0     0     0[ 1] .head.text        PROGBITS         ffffffc0 10080000  000100000000000000001000  0000000000000000  AX       0     0     4096[ 2] .text             PROGBITS         ffffffc010081000  0001100000000000011ae294  0000000000000000 WAX       0     0     4096[ 3] .rodata           PROGBITS         ffffffc011230000  011c00000000000000c11d3d  0000000000000000 WAMS       0     0     4096

段 [1] 为 .head.text 段,我们看到其入口地址就是 0xFFFF FFC0 1008 0000

2.3 .text 段

	.text : {			/* Real text segment		*/_stext = .;		/* Text and read-only data	*/__exception_text_start = .;*(.exception.text)__exception_text_end = .;IRQENTRY_TEXTSOFTIRQENTRY_TEXTENTRY_TEXTTEXT_TEXTSCHED_TEXTCPUIDLE_TEXTLOCK_TEXTKPROBES_TEXTHYPERVISOR_TEXTIDMAP_TEXTHIBERNATE_TEXTTRAMP_TEXT*(.fixup)*(.gnu.warning). = ALIGN(16);*(.got)			/* Global offset table		*/}. = ALIGN(SEGMENT_ALIGN);_etext = .;			/* End of text section */

开始的时候,将当前位置存放在 _stext 和 __exception_text_start 中;

接着加入所有输入目标文件的  .exception.text 段到 .text 段中;

添加完 .exception.text 后,将当前位置存入  __exception_text_end 中;

接着是宏定义  IRQENTRY_TEXT,定义在 vmlinux.lds.h 中:

include/asm-generic/vmlinux.lds.h#define IRQENTRY_TEXT							\ALIGN_FUNCTION();					\__irqentry_text_start = .;				\*(.irqentry.text)					\__irqentry_text_end = .;

以此类推,最终 .text 段中依次输入:

  • .exception.text;
  • .irqentry.text;
  • .softirqentry.text;
  • .entry.text;
  • ...
  • .fixup;
  • .gnu.warning;
  • .got;

最后将当前位置存入 _etext 中。

2.4 .rodata 段

RO_DATA(PAGE_SIZE)		/* everything from this point to     */

该宏定义是在 vmlinux.lds.h:

include/asm-generic/vmlinux.lds.h#define RO_DATA(align)  RO_DATA_SECTION(align)#define RO_DATA_SECTION(align)						\. = ALIGN((align));						\.rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {		\__start_rodata = .;					\*(.rodata) *(.rodata.*)					\RO_AFTER_INIT_DATA	/* Read only after init */	\. = ALIGN(8);						\__start___tracepoints_ptrs = .;				\KEEP(*(__tracepoints_ptrs)) /* Tracepoints: pointer array */ \__stop___tracepoints_ptrs = .;				\*(__tracepoints_strings)/* Tracepoints: strings */	\}								\\.rodata1          : AT(ADDR(.rodata1) - LOAD_OFFSET) {		\*(.rodata1)						\}								\\/* PCI quirks */						\.pci_fixup        : AT(ADDR(.pci_fixup) - LOAD_OFFSET) {	\__start_pci_fixups_early = .;				\KEEP(*(.pci_fixup_early))				\__end_pci_fixups_early = .;				\__start_pci_fixups_header = .;				\KEEP(*(.pci_fixup_header))				\__end_pci_fixups_header = .;				\__start_pci_fixups_final = .;				\KEEP(*(.pci_fixup_final))				\__end_pci_fixups_final = .;				\__start_pci_fixups_enable = .;				\KEEP(*(.pci_fixup_enable))				\__end_pci_fixups_enable = .;				\__start_pci_fixups_resume = .;				\KEEP(*(.pci_fixup_resume))				\__end_pci_fixups_resume = .;				\__start_pci_fixups_resume_early = .;			\KEEP(*(.pci_fixup_resume_early))			\__end_pci_fixups_resume_early = .;			\__start_pci_fixups_suspend = .;				\KEEP(*(.pci_fixup_suspend))				\__end_pci_fixups_suspend = .;				\__start_pci_fixups_suspend_late = .;			\KEEP(*(.pci_fixup_suspend_late))			\__end_pci_fixups_suspend_late = .;			\}								\\/* Built-in firmware blobs */					\.builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) ALIGN(8) {	\__start_builtin_fw = .;					\KEEP(*(.builtin_fw))					\__end_builtin_fw = .;					\}								\\TRACEDATA							\\/* Kernel symbol table: Normal symbols */			\__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\__start___ksymtab = .;					\KEEP(*(SORT(___ksymtab+*)))				\__stop___ksymtab = .;					\}								\\/* Kernel symbol table: GPL-only symbols */			\__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\__start___ksymtab_gpl = .;				\KEEP(*(SORT(___ksymtab_gpl+*)))				\__stop___ksymtab_gpl = .;				\}								\\/* Kernel symbol table: Normal unused symbols */		\__ksymtab_unused  : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) {	\__start___ksymtab_unused = .;				\KEEP(*(SORT(___ksymtab_unused+*)))			\__stop___ksymtab_unused = .;				\}								\\/* Kernel symbol table: GPL-only unused symbols */		\__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \__start___ksymtab_unused_gpl = .;			\KEEP(*(SORT(___ksymtab_unused_gpl+*)))			\__stop___ksymtab_unused_gpl = .;			\}								\\/* Kernel symbol table: GPL-future-only symbols */		\__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \__start___ksymtab_gpl_future = .;			\KEEP(*(SORT(___ksymtab_gpl_future+*)))			\__stop___ksymtab_gpl_future = .;			\}								\\/* Kernel symbol table: Normal symbols */			\__kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {		\__start___kcrctab = .;					\KEEP(*(SORT(___kcrctab+*)))				\__stop___kcrctab = .;					\}								\\/* Kernel symbol table: GPL-only symbols */			\__kcrctab_gpl     : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) {	\__start___kcrctab_gpl = .;				\KEEP(*(SORT(___kcrctab_gpl+*)))				\__stop___kcrctab_gpl = .;				\}								\\/* Kernel symbol table: Normal unused symbols */		\__kcrctab_unused  : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) {	\__start___kcrctab_unused = .;				\KEEP(*(SORT(___kcrctab_unused+*)))			\__stop___kcrctab_unused = .;				\}								\\/* Kernel symbol table: GPL-only unused symbols */		\__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \__start___kcrctab_unused_gpl = .;			\KEEP(*(SORT(___kcrctab_unused_gpl+*)))			\__stop___kcrctab_unused_gpl = .;			\}								\\/* Kernel symbol table: GPL-future-only symbols */		\__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \__start___kcrctab_gpl_future = .;			\KEEP(*(SORT(___kcrctab_gpl_future+*)))			\__stop___kcrctab_gpl_future = .;			\}								\\/* Kernel symbol table: strings */				\__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\*(__ksymtab_strings)					\}								\\/* __*init sections */						\__init_rodata : AT(ADDR(__init_rodata) - LOAD_OFFSET) {		\*(.ref.rodata)						\MEM_KEEP(init.rodata)					\MEM_KEEP(exit.rodata)					\}								\\/* Built-in module parameters. */				\__param : AT(ADDR(__param) - LOAD_OFFSET) {			\__start___param = .;					\KEEP(*(__param))					\__stop___param = .;					\}								\\/* Built-in module versions. */					\__modver : AT(ADDR(__modver) - LOAD_OFFSET) {			\__start___modver = .;					\KEEP(*(__modver))					\__stop___modver = .;					\}								\\BTF								\\. = ALIGN((align));						\__end_rodata = .;

2.5 __ex_table 段

EXCEPTION_TABLE(8)		/* __init_begin will be marked RO NX */

该宏定义也是在 vmlinux.lds.h:

include/asm-generic/vmlinux.lds.h#define EXCEPTION_TABLE(align)						\. = ALIGN(align);						\__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {		\__start___ex_table = .;					\KEEP(*(__ex_table))					\__stop___ex_table = .;					\}

2.6 .notes 段

NOTES

该宏定义也是在 vmlinux.lds.h: 

include/asm-generic/vmlinux.lds.h#define NOTES								\/DISCARD/ : { *(.note.GNU-stack) }				\.notes : AT(ADDR(.notes) - LOAD_OFFSET) {			\__start_notes = .;					\KEEP(*(.note.*))					\__stop_notes = .;					\}

 

2.7 

这篇关于Linux 内核连接脚本vmlinux.lds.S的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/341378

相关文章

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法

《ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法》本文介绍了Elasticsearch的基本概念,包括文档和字段、索引和映射,还详细描述了如何通过Docker... 目录1、ElasticSearch概念2、ElasticSearch、Kibana和IK分词器部署

Linux流媒体服务器部署流程

《Linux流媒体服务器部署流程》文章详细介绍了流媒体服务器的部署步骤,包括更新系统、安装依赖组件、编译安装Nginx和RTMP模块、配置Nginx和FFmpeg,以及测试流媒体服务器的搭建... 目录流媒体服务器部署部署安装1.更新系统2.安装依赖组件3.解压4.编译安装(添加RTMP和openssl模块

linux下多个硬盘划分到同一挂载点问题

《linux下多个硬盘划分到同一挂载点问题》在Linux系统中,将多个硬盘划分到同一挂载点需要通过逻辑卷管理(LVM)来实现,首先,需要将物理存储设备(如硬盘分区)创建为物理卷,然后,将这些物理卷组成... 目录linux下多个硬盘划分到同一挂载点需要明确的几个概念硬盘插上默认的是非lvm总结Linux下多

SQL 中多表查询的常见连接方式详解

《SQL中多表查询的常见连接方式详解》本文介绍SQL中多表查询的常见连接方式,包括内连接(INNERJOIN)、左连接(LEFTJOIN)、右连接(RIGHTJOIN)、全外连接(FULLOUTER... 目录一、连接类型图表(ASCII 形式)二、前置代码(创建示例表)三、连接方式代码示例1. 内连接(I

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

java如何通过Kerberos认证方式连接hive

《java如何通过Kerberos认证方式连接hive》该文主要介绍了如何在数据源管理功能中适配不同数据源(如MySQL、PostgreSQL和Hive),特别是如何在SpringBoot3框架下通过... 目录Java实现Kerberos认证主要方法依赖示例续期连接hive遇到的问题分析解决方式扩展思考总

10个Python自动化办公的脚本分享

《10个Python自动化办公的脚本分享》在日常办公中,我们常常会被繁琐、重复的任务占据大量时间,本文为大家分享了10个实用的Python自动化办公案例及源码,希望对大家有所帮助... 目录1. 批量处理 Excel 文件2. 自动发送邮件3. 批量重命名文件4. 数据清洗5. 生成 PPT6. 自动化测试

使用Java实现一个解析CURL脚本小工具

《使用Java实现一个解析CURL脚本小工具》文章介绍了如何使用Java实现一个解析CURL脚本的工具,该工具可以将CURL脚本中的Header解析为KVMap结构,获取URL路径、请求类型,解析UR... 目录使用示例实现原理具体实现CurlParserUtilCurlEntityICurlHandler