【System Beats!】第七章 链接

news/2025/11/14 18:39:44/文章来源:https://www.cnblogs.com/namelessstory/p/19223080

链接

相关定义

  • 即将各种代码和数据片段收集并组合成为一个单一文件的过程。
  • 主要任务:符号解析与重定位
  • 目标文件:编译器将源代码文件编译后的产物,但还未加载链接为最后的可执行文件。
  • 可执行文件:链接后的最终产物,这个文件可被加载进内存并执行。
  • 链接可在编译时、加载时、运行时均可执行。

链接的动机

  • 模块化:支持将程序分解为独立的模块进行开发和维护,提高代码可重用性和可管理性。
  • 提高时间效率:允许并行编译不同的模块,从而减少编译时间,修改某个模块后只需重新编译该模块并链接。
  • 提高空间效率:静态链接下,可执行文件只包含实际使用的库函数,减少了文件大小;动态链接允许多个进程共享内存中库代码,进一步节省内存和磁盘空间。

编译过程

  • gcc充当编译器驱动程序,代表用户在需要时调用语言预处理器、编译器、汇编器和链接器。
  • 预处理:由cpp进行C 预处理,处理源代码中以#开头的指令,将xx.c翻译为一个ASCII码的中间文件xx.i
  • 可以使用gcc -E src.c -o src.i进行操作。
  • 编译:由cc1,即C 编译器进行编译,翻译为汇编语言,生成一个ASCII码的汇编文件xx.s
  • 可以使用gcc -S src.c -o src.s进行操作。
  • 汇编:汇编器as将汇编语言翻译为机器语言,生成可重定位的目标文件xx.o,文件中包含不同的代码和数据节。
  • 可以使用gcc -c src.c -o src.o进行操作。
  • 链接:链接器ldxx.o和其他的xx.o,以及必要的系统库文件,合并为可执行文件prog
  • 可以使用gcc src.o -o executable进行操作。

静态链接

  • 链接器需要实现符号解析和重定位两个任务。
  • 以一组可重定位目标文件和命令行参数作为输入。
  • 输出一个完全链接的、可以加载和运行的可执行目标文件作为输出。
  • 符号解析:将符号引用和输入的可重定位目标文件中的符号表中一个确定文件关联起来。
  • 重定位:合并重定位输入模块,将符号定义跟一个地址关联起来,并为找到的每个符号指向对应的地址。

目标文件

  • 可重定位目标文件(.o):包含机器代码和数据,无法单独运行。
  • 可执行目标文件(.out/.exe等):包含机器代码和数据,可以单独运行。
  • 共享目标文件(.so(Linux)/.dll(Win)):特殊的可重定位目标文件,可以在加载或运行时被动态加载进内存并链接。

可重定位目标文件

  • ELF头:以16字节序列开始,描述生成该文件的系统的字的大小和字节顺序。
  • 其它部分包含帮助链接器语法分析和解释目标文件的信息,包括ELF头大小、目标文件类型,机器类型,节头部表的文件偏移,节头部表中条目大小及数量。
  • 运行时,根据以上信息,先定位到ELF头,再根据其信息找到节头部表,再根据节头部表找到相应的节。
  • 节的组成:
    • .text:已编译程序的机器代码
    • .rodata:只读数据
    • .data:已初始化的全局与静态变量
    • .bss:未初始化的全局和静态变量,以及被初始化为0的全局和静态变量
    • 被初始化为0的变量到运行时才到内存中分配空间,.bss中只有大小和位置。
    • .symtab:符号表,存放定义和引用的函数与全局变量,不包含局部变量。
    • .rel.text:重定位信息,调用外部函数或引用全局变量才需要修改。
    • .rel.data:重定位信息,已初始化的全局变量才需要修改。
    • .strtab:字符串表,包含.debug.symtab中符号表和节头部的节名字,以null(\0)结尾的字符串序列。
    • .debug:调试符号表,只有-g调用时才产生。
    • .line:原始C程序的行号和.text中机器指令的映射,只有-g调用才产生。
    • 节头部表:存储不同部分起始位置。

符号与符号表

  • 每个可重定位目标模块都有一个符号表,包含符号的定义和引用详情。
  • 有三种不同的符号:
    • 全局符号:由其定义并且能被其它模块引用,对应非静态函数与全局变量。
    • 局部符号:由其定义且仅能在其内使用,对应静态函数、全局变量,在该模块任意位置都可见。
    • 外部符号:由其引用但在其内未定义,由其他模块定义。
  • 局部变量存在栈中,而非符号表中。
  • 静态成员只能在其定义模块内使用,编译器在.data.bss中分配空间,创造仅有唯一名字的符号。
  • 若不同模块中有重名,则会生成x.1与``x.2`加以区分。
  • 符号表的结构:
    • namestrtab中的偏移,指向符号以NUll结束的字符串名字。
    • value:对于可重定位模块来说,相对于定义所在节其实的偏移。
    • 对于可执行目标文件,是绝对运行时地址。
    • size:目标大小(以字节为单位)。
    • type:符号类型,函数/数据。
    • binding:符号类型,本地/全局。
    • section:符号所在的节。
  • 三个伪节(节头部表中不存在)
    • UNDEF:未定义符号,在本目标模块中引用,其它地方定义。
    • COMMON:还未被分配位置的未初始化的数据目标,即未初始化的全局变量(可能定义于其他模块中,而.bss则必然定义于当前模块)。
    • 一个未初始化的全局变量,会放在COMMON中,若用fno-common编译,则全部都放在.bss中。
    • 其中,value给出对齐要求,size给出最小大小。
    • ABS:不该被重定位的符号。

符号解析

  • 全局符号被人为分类:
    • 强符号:函数和已初始化的全局变量
    • 弱符号:未初始化的全局变量
  • 相关规则:
    • 不允许有多个同名强符号
    • 如果一个强符号和多个弱符号同名,选择强符号
    • 若多个弱符号同名,任意选择一个
  • 因此,为避免规则三带来的麻烦,尽量使用static定义全局变量。
  • 尤其是,当同名符号类型不同时,可能导致严重错误,比如覆盖其他变量或者非法访问。
  • 因此,当文件A有一个弱符号x时,它不知道之后是否有强符号x,此时会放到COMMON中等待取舍。

静态库

  • 一组目标文件的集合,通过将它们打包成一个单独的文件,实现代码重用。
  • 编译时链接到应用程序中,生成一个包含所有代码的可执行文件。
  • 使用静态库的好处:
    • 若让编译器辨认出队标准函数调用,则会因大量标准函数显著增加编译器复杂性,而且需要频繁更新编译器。
    • 若将所有标准函数都放在一个单独可重定位目标模块中,再链接到可执行文件,则每个可执行文件都包含一份其完全副本,是对磁盘和内存的浪费,并且需要每次重新编译。
    • 若将每个标准标准函数都创建一个独立可重定位文件,则需要显示链接目标模块,容易出错。
  • 因此,相关函数可被编译为独立目标模块,然后封装为单独静态库文件。
  • 链接时,只复制被引用的目标模块。
  • 静态库以存档文件格式存放在磁盘中,存档文件是一组链接起来的可重定位目标文件的集合,有一个头部用来描述每个成员文件的大小和位置,用.a标识。
  • 创建静态库:
    • 编译源文件生成目标文件:gcc -c addvec.c multvec.c
    • 使用ar工具将目标文件打包为静态库:ar rcs libvector.a addvec.o multvec.o
  • 使用静态库:
    • 编译使用静态库的程序文件:gcc -c main2.c
    • 链接生成可执行文件,指定静态库位置:gcc -static -o prog2c main2.o ./libvector.a,使用-static关键字指定静态链接。
    • 也可以使用-L-l参数:gcc -static -o prog2c main2.o -L. -lvector
  • 解析静态库引用:
    • 定义:E为最终需要的成员目标文件,U为未解析的符号,D为已定义的符号。
    • 检测命令行的每个输入文件,若为目标文件则直接读入,若为存档文件,尝试匹配未解析符号和存档文件成员定义的符号,若有定义则加,没有则丢弃。
    • 解析完成后,若U非空,则链接器报错并终止。
  • 因此得出,命令行的文件顺序非常重要,需要遵循拓扑排序,因此有的存档文件可能需要多次出现在命令行中。

重定位

  • 由两步组成:
    • 重定位节和符号定义:需要将所有相同类型的节合并为同一类型的聚合节,同时将运行时内存地址赋给新的聚合节以及其中每个节。
    • 重定位符号:修改代码节和数据节中对每个符号的引用,使得它们指向正确的运行时地址,依赖于可重定位目标模块中称为重定位条目的数据结构。
  • 重定位条目:由汇编器生成,告诉链接器在合并时如何修改这个引用。
  • 代码的重定位条目放在.rel.text中,数据的重定位条目放在.rel.data中。

  • 重定位类型:
    • R_X86_64_PC32:重定位一个使用32位PC相对地址的引用。
    • R_X86_64_32:重定位一个使用32位绝对地址的引用。
  • 重定位过程:

  • 假设ADDR(s)ADDR(r.symbol)表示运行时地址,与之相对,s表示未进行重定位时,原始目标文件的地址。
  • 因此,首先计算需要修改的地址的原始位置refptr
  • 随后,利用偏移量不变,得到引用的运行时地址refaddr
  • r.addend的定义是,补偿refaddr与运行时PC之间的差值,即 refaddr=ADDR(PC)+r.addend
  • 因此得到以下式子:PC=refaddr-r.addend以及PC+*refptr=ADDR(r.sumbol)
  • 即得到图中*refptr的相对地址。
  • 考虑绝对重定位,只需要将r.addend看成0,即得到*refptr=ADDR(r.symbol)+r.addend,即得到*refptr=ADDR(r.sumbol)+r.addend,也就是不需要考虑上面的公式。
  • 下面是相对重定位和绝对重定位的例子

可执行目标文件

  • 在这里,一个组织不再被称为节,而是称为段,即链接器根据目标文件中属性相同的多个节合并后的节的集合。
  • ELF头:描述文件的整体格式,包括程序的入口点(运行时执行的第一条指令地址)。
  • .init:比可重定位目标文件多出的,包括初始代码(即_init函数),在程序开始时调用。
  • .text/.rodata/.data:与节的定义相似,但是已经被重定位了。
  • .rel.text/.rel.data不再存在,因为已经完全链接。
  • 段与节的定义对比:
    • 段代表的是可执行代码和数据等内存区域,段是根据内存区域划分的。
    • 节代表文件中的一组相关数据,根据功能和目的来划分。
  • 例如,上述即分为读/执行数据段/代码段/r_x,以及读写数据段/数据段/rw_
  • 可执行文件的连续的片被映射到连续的内存段,程序头部表描述了这种映射关系。

加载可执行目标文件

  • 其大致分布如上
  • 加载:将可执行目标文件的代码和数据复制到内存。
  • 实现:加载器将可执行目标文件的代码和数据复制到内存中,随后通过跳转到程序的第一条指令或入口点来运行该程序。
  • 代码段从0x400000,即 \(2^{22}\) 开始,后面是数据段。
  • 堆内存:在数据段之后,通过调用malloc向上增长。
  • 用户栈:从最大的合法用户地址,即 \(2^{48}-1\) 开始,向下增长。
  • 栈上方的区域,为内存的代码与数据保留。
  • 由于.data段有对齐要求,因此代码段与数据段之间有空隙。
  • 在分配栈、共享库和堆段运行读地址时,链接器使用地址空间布局随机化,造成这其中有空隙。但是,它们的相对位置不变。
  • 加载器运行时,在程序头部表引导下,将可执行文件的片复制到代码段和数据段,接着跳转到_start的地址,即程序入口点(于ctrl.c中定义,对所有C程序都相同),其调用系统启动函数_libc_start_main(定义于libc.so中),初始化执行环境,调用main函数,处理其返回值,必要时将控制返回给内核。

动态链接共享库

  • 静态库需要定期维护和更新
  • 标准函数会被复制到每个运行进程的文本段中,是对内存的浪费。
  • 动态链接:在运行时被动态加载和连接的库文件。
  • C标准库libc.so通常是动态链接的。
  • 首先使用以下指令来创建共享库.so文件:
gcc -shared -fPIC math.c -o libmath.so
# -shared指示gcc生成共享库文件;-fPIC指示gcc生成位置无关代码
# 使得gcc在当前目录下生成名为libmath.so的共享库文件
  • 随后使用共享库编译主程序:
gcc main.c -lmath -L. -o main
  • lmath指示链接器使用libmath.soL.指定库的搜索路径为当前目录。

加载时链接

  • 其运行流程通常如下:

  • 任意给定的文件系统中,对于一个库只有一个.so文件,所有引用该库的可执行目标文件共享其中代码和数据。
  • 内存中,一个共享库的.text节的一个副本可以被不同的正在运行的进程共享。
  • 链接器:负责在编译过程之后工作,将多个目标文件和库文件链接为一个可执行文件或库文件。
  • 加载器:在程序执行阶段工作,将可执行文件加载到内存并准备好执行环境。
  • 动态链接器:在加载器将程序加载到内存后、程序开始执行前工作,负责在运行时加载动态库和解析符号(进行重定位)。
  • 实际进行加载时链接时,静态链接器ld将共享库的重定位和符号表等信息到可执行文件中,加载器加载程序时,检测到.interp节,其中包含动态链接器id.so路径。加载器调用动态链接器,将程序和共享库的代码和数据进行完全链接,最后将控制权交给程序。

运行时链接

  • 程序运行时,每次需要使用库函数时才进行动态链接。
  • 允许在运行时修改库函数,方便维护长期运行的程序。
  • 更新时仅需更新共享库,但是每次调用函数都需要链接。
  • 可以通过void *dlopen(const char *filename,int flag)来实现加载和连接共享库。
  • flag从以下几个参数中选择一个或多个,使用按位与|进行连接:
    • RTLD_LAZY:仅在需要时解析符号,可加快程序启动速度。
    • RTLD_NOW:立即解析所有符号,在库加载时就进行,有助于尽早捕获未解析的符号错误。
    • RTLD_GLOBAL:使得该库中的符号对于随后加载的所有库可见,可以用于跨库共享符号,但是可能引起符号冲突。
    • RTLD_LOCAL:默认,将符号的可见性限制在加载该库的上下文中,后续加载的库无法访问这些符号。
  • 该函数返回一个void*句柄,可以理解为指向共享库的指针,出错则返回NULL
  • void *dlsym(void* handle,char* symbol):解析handle指向的共享库中symbol对应的符号,若没有则返回NULL
  • int dlclose(void* handle):关闭并卸载共享库,成功返回0,失败返回-1。
  • 也可以在dlopen时选择宏NTLE_NODELETE,使dlclose不会卸载共享库。
  • 以下为一份运行时链接的模板:
#include <dlfcn.h>void *handle = dlopen("libmath.so", RTLD_LAZY);
if (!handle) // 错误处理void *func = dlsym(handle, "my_function");
if (!func)  // 错误处理// 使用函数指针调用函数
typedef int (*my_function_t)(int, int);
my_function_t my_function = (my_function_t) func;
int result = my_function(1, 2);dlclose(handle);
  • 动态链接器的工作流程如下:
    • 查找共享库:基于环境变量LD_LIBRARY_PATH 和系统默认路径,查找共享库在磁盘中的位置。
    • 内存映射:将共享库的各个段映射到进程的虚拟地址空间,.text段在多个进程间共享物理内存页,.data.bss段使用写时复制(Copy on write,COW)机制。
    • 符号解析与重定位:解析共享库中的符号,并执行重定位,使进程能够调用共享库提供的函数和访问变量。

位置无关代码/PIC

  • 共享库的主要目的是允许多个正在运行的进程共享内存中相同的库代码。
  • 若每个共享库分配固定位置,则对地址空间的使用效率不高,同时难以管理。
  • 因此,提出位置无关的概念,即共享库可以被加载到内存的任何为止,从而多个程序可以同时使用同一个共享库示例,节省内存。
  • 可以加载,但无须重定位的代码称为位置无关代码/PIC
  • 需要使用-fpic选项编译共享库,换言之,共享库的编译必须总是使用该选项。
  • 对一个目标模块中符号的引用是不需要特殊处理使之成为PIC,可以用PC相对寻址来编译这些引用,构造目标文件时由静态链接器定位。
  • 生成全局变量的PIC引用,需要使用过程链接表/PLT全局偏移表/GOT

PIC数据引用

  • 基于一个事实:无论在内存中何处加载一个目标模块,数据段和代码段的距离总是保持不变,代码段中任意指令和数据段中任意变量的距离都是一个运行时常量,与绝对位置无关。
  • 从数据段创建的地方创建了一个表,叫做全局偏移量表
  • GOT中,每个被这个目标模块引用的全局数据目标(即过程或全局变量)都有一个8字节条目。
  • 编译器为GOT中每个条目生成一个重定位记录。
  • 加载时,动态链接器重定位GOT中每个条目,使其包含目标的正确绝对地址,每个引用全局目标的目标模块都有自己的GOT
  • 编译器可以通过利用代码段和数据段之间不变的距离,产生PC直接相对引用,并且增加一个重定位,让链接器在构造这个共享模块时解析它。

PIC函数调用

  • 访问其他目标模块中的全局函数,由于共享库中的全局函数远远多于全局变量,而一般的程序只会调用少量全局变量,却频繁调用函数,如果仍然采用全局变量的访问模式来调用全局函数(即使用GOT进行二次跳转),则需要对极多个GOT条目进行重定位,造成严重资源浪费。
  • 因此,GCC采用延迟绑定策略(思想跟懒删除堆/延迟标记线段树/缓存相同),将函数地址的绑定推迟到第一次调用该过程时,有效避免动态链接器在加载时进行不必要的重定位。
  • 若目标模块调用共享库中的函数,则其有自己的GOTPLT
  • PLT是代码段的一部分,每个条目占用16字节(回忆Attack Lab,函数地址需要对16字节对齐)。
  • PLT实际上是模块访问全局函数的一次索引,已被设置好且始终不变;GOT是二次索引,初始状态没被设置好,需要在函数被调用时被设置。
  • 如下图所示,其是一个GOTPLT的演示:

  • PLT每个条目是长为16字节的代码,第0项调用动态链接器,格式为push+jmp;第1项为调用系统启动函数,之后每一项都用于调用一个函数,格式为jmp (GOT对应索引)+push(函数信息)+jmp(PLT第0项,调用动态链接器)
  • GOT的第0、第1个条目记录了动态链接器解析函数地址中会使用的信息,第2个条目是动态链接器(在ld.so)中的入口点;之后每一项都维护者函数地址,初始设置为对应PLT条目的第二条。
  • 第一次调用函数时,跳转到PLT对应条目,条目第一行跳转到GOT对应条目指向位置。
  • GOT未被设置好,所以小赚回PLT条目第二行,它将要定位的函数ID压栈。
  • 跳转到PLT第0项,它将GOT[1]指向的重定位条目压栈,调用GOT[2]指向的动态链接器。
  • 动态链接器根据栈中的两个参数(ID和重定位条目),重写GOT对应条目为函数地址,再把控制传递给对应函数。
  • 由于全部过程中没有ret,对应函数执行完毕后直接ret到调用函数的位置。

打桩

  • 即在运行时替换库函数的行为

编译时打桩

  • 通过在编译源代码时插入打桩函数实现。
  • 使用-I选项指定头文件路径。
  • 编译命令:gcc -I. -o intc int.c mymalloc.o
  • 含义:
    • -I:告诉编译器在当前目录.中查找头文件
    • -o intc:指定输出文件名为intc
    • int.c:源文件
    • mymalloc.o:自定义动态库
  • 这样,会在搜索malloc时,在搜索通常的系统目录之前,优先在当前目录中搜索malloc.h

链接时打桩

  • 在链接阶段,用自定义函数替换标准库函数。
  • 使用--warp选项告诉链接器用自定义函数替换标准函数。


运行时打桩

  • 在程序运行时,动态替换库函数。
  • 通过使用LD_PRELOAD环境变量加载自定义动态库实现。
gcc -shared -fpic -o mymalloc.so mymalloc.c -ldl
LD_PRELOAD="./mymalloc.so" ./myprogram
  • -shared:生成共享库
  • -fpic:生成位置无关代码,这是共享库必需的,因为共享库可以加载到内存中的任意位置。
  • -ldl:链接动态链接器库,libdl是动态链接器库。
  • LD_PRELOAD:环境变量,指定在运行程序时加载的自定义动态库。

后记

  • 写得好累,还有第八章的没写

alt text

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

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

相关文章

oracle 11g r2 linux

你提到的 "Oracle 11g R2 Linux" 是 Oracle 数据库的一个版本,主要用于 Linux 系统。以下是一些与 Oracle 11g R2 在 Linux 上相关的关键信息和命令示例,帮助你了解如何在 Linux 环境中安装、配置和管理 O…

实用指南:接口测试 | 使用Postman实际场景化测试

实用指南:接口测试 | 使用Postman实际场景化测试2025-11-14 18:35 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; displa…

应用程序建立的数据库连接,也就是非交互式连接 是什么时候开始的?什么时候结束?连接结束后 会影响应用程序操作db失败吗? 还有就是如果连接关闭了 会立马重新建立新的连接吗?

问题: 应用程序建立的数据库连接,也就是非交互式连接 是什么时候开始的?什么时候结束?连接结束后 会影响应用程序操作db失败吗? 还有就是如果连接关闭了 会立马重新建立新的连接吗?解答: 我们讨论的是应用程序通…

2025高压合金管实力厂家推荐榜:5310/6479 高压合金管型号领衔,天津大无缝联合钢铁有限公司五星领跑工业用材赛道

在工业生产、能源输送等场景中,合金管、高压合金管的品质直接影响设备运行稳定性,5310 高压合金管与 6479 高压合金管更是核心刚需产品。2025 年榜单聚焦产品性能、技术实力与应用适配性,精选 4 家优质企业,为采购…

Kafka协调器:消费者组管理与重平衡机制 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

#题解#洛谷P1884#二维离散化#

传送门 分析x,y的范围-1e8~1e8,需要离散化。定义f[i][j]是左上角(ci,cj)右下角(c(i+1),c(j+1))染色情况代码实现 #include<bits/stdc++.h> using namespace std; #define MAXN 4010 int n, btop, ctop; int…

HarmonyOS应用配置文件与资源组织深度解析 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025扫描电镜精选榜:富泰微五星领衔,日立、国仪携超高分辨率/钨灯丝 SEM,适配科研工业多元需求

随着纳米科技与材料科学的发展,扫描电镜(SEM)已成为微观表征核心设备,涵盖进口与国产、钨灯丝与场发射、FIB 与超高分辨率等多元类型。2025 年榜单聚焦技术实力与用户口碑,精选 3 家优质企业,为不同场景提供精准…

2025济南单招综评培训机构排行榜:3 家实力学校口碑出圈 易升教育五星优选 解锁适配不同考生的升学备考靠谱路径

随着单招综评成为多元升学的重要路径,济南单招综评培训市场愈发成熟。本文结合办学资质、师资实力、升学成果及口碑反馈,精选 3 家优质济南单招综评机构,其中济南易升教育学校以全维度优势获评五星推荐,为考生提供…

2025山东公考面试/笔试/考试/辅导培训五星推荐榜:三家优质机构精准适配备考需求,助力高效上岸

2025年公考竞争持续升温,优质的公考培训、公考面试培训、公考笔试培训成为考生高效备考的关键。本次推荐榜聚焦口碑与实效,精选 3 家五星公考辅导机构,为不同基础、不同场景的考生提供靠谱参考。 山东邦荣公考【推荐…

2025智能科技/医疗设备/信息科技/新中式茶饮/科创/平面/东方美学/品牌设计/品牌logo设计/品牌VI设计领域优质公司排行榜:聚焦全案创意与视觉赋能,3 家机构助力品牌高效破圈

在商业竞争日趋激烈的当下,品牌设计成为企业构建差异化优势、精准触达受众的核心抓手。品牌全案设计、品牌 VI 设计、品牌 logo 设计等服务,既塑造品牌外在辨识度,更传递核心价值,驱动商业影响力升级。2025 年,一…

2025修护/二硫化硒去屑/香氛/控油蓬松/洗发水品牌推荐榜:精准护养新选择,MASIL玛丝兰领衔解决头屑、扁塌等护发难题

随着生活节奏加快,头皮出油、头屑反复、发丝干枯等问题愈发常见,一款适配自身发质的洗发水成为日常护理的刚需。经过市场口碑筛选与成分功效验证,2025年值得关注的洗发水品牌榜单新鲜出炉,其中既有深耕护发领域的实…

2025防火/模压/瓦楞/大跨距/热镀锌/热浸锌/不锈钢/光伏/铝合金/锌铝镁电缆桥架优选榜:河北百著全系列防护覆盖 三家实力厂家凭场景优势突围

随着工业建设与新能源产业的快速发展,电缆桥架作为电力传输核心配套设备,其品质与场景适配性备受关注。2025 年榜单聚焦产品多样性、技术实力与工程口碑,精选三家优质企业,其中河北百著金属制品有限公司以全系列布…

2025厨房/无烟管/商用/复合式/内循环/小型/油烟净化/一体机推荐榜:上海多环五星领跑 全场景适配解锁餐饮 / 家用净化新体验

2025年油烟净化需求向 “高效合规、场景细分、节能智能” 升级,油烟净化一体机成为商用与家用市场主流。上海多环领衔三大实力企业,以核心技术与全场景适配能力,为厨房、餐饮等场景提供优质解决方案。 上海多环油烟…

2分钟选刊!值得农林环境人收藏的6个期刊!境科研人必备!

AMiner期刊会议检索全面升级,助力农业与环境科学领域高效选刊!AMiner 收录了10万余种高质量期刊会议,共覆盖100+全一级学科, 期刊会议检索页全面升级 :AMiner期刊/会议:https://www.aminer.cn/open/journal/?f=f…

antd 上传文件组件在表单回显时不显示下载按钮

antd 上传文件组件预览和下载分开处理,设置showDownloadIcon后正常上传后可以显示下载按钮,但是在表单回显时不显示下载按钮之前需求方提出说想要给表单上传的文件增加预览功能,原来点击展示列表中的文件时,docx文…

2025武汉车出租厂家推荐榜:防撞车出租/高空车出租/登高车出租/服务体验与高性价比深度解析

随着日常出行、企业运营对车辆需求的日益增长,车出租服务已成为便捷高效的解决方案。但市场上品牌繁杂,车辆品质、服务效率参差不齐,让用户挑选时倍感困扰。为帮助大家精准避坑,本文基于真实市场调研,筛选出 2025…

2025滚齿机优质厂家推荐榜:济南兴宇数控五星领跑,三大厂商凭技术与适配性成行业标杆

2025年齿轮加工领域对滚齿机的精度、效率与场景适配性需求持续升级,一批深耕技术研发的企业脱颖而出。本次榜单聚焦行业优质厂商,以产品实力、市场口碑为核心维度,精选 4 家代表性企业,其中济南兴宇数控设备有限公…

2025年芝麻白/芝麻灰/火烧面/亚光面/花岗岩/路岩石优质厂家优选榜:聚焦专业品质,助力工程建设

一、引言:花岗岩路岩石市场发展与优选意义 在市政建设、园林景观及建筑装饰等领域,花岗岩路岩石凭借其优异的物理性能和美观度,成为不可或缺的建材选择。2025 年,市场对花岗岩路岩石的需求持续增长,消费者在选购时…

102302141_易敏亮第三次数据采集作业

课程链接 https://edu.cnblogs.com/campus/fzu/2025DataCollectionandFusiontechnology作业链接 https://gitee.com/lisu6/data_collect/tree/master/3作业1当当多线程 https://gitee.com/lisu6/data_collect/tree/mas…