深入理解计算机系统第七章知识点总结

news2024/11/27 7:33:23

文章目录

  • 详解`ELF`文件-> `main.o`
    • 前十六个字节的含义
    • 推测`elf`的大小
    • 查看节头部表
      • 推断每个`section`在`elf`中的具体位置
      • 查看`.text`的内容
      • 查看`.data`的内容
      • 关于`.bss`
      • 查看`.rodata`的内容
      • 关于其他的节表示的信息
    • 详解符号表
    • 符号
    • 编译器如何解析多重定义的全局符号
    • 静态库与静态链接
    • 构造和使用一个静态库
    • 静态库的解析过程
  • 重定位
    • 重定位节(`section`)和重定位符号定义
    • 重定位节中的符号引用
  • 可执行目标文件
    • 加载可执行目标文件
    • 加载运行过程细节
  • 共享库
    • 构造一个共享库
    • 使用共享库
    • 解释共享库工作原理

详解ELF文件-> main.o

  • elf文件可以分成三部分

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sfedvODD-1684661656490)(E:\csdn_blog博客\大三\上\计算机系统二\image\elf.png)]

    • ELF头——ELF header
    • 不同的section——Sections
    • 以及描述这些section信息的表——Section header table

假设有如下main.c文件

#include<stdio.h>

int count = 10;
int value;

void func(int sum)
{
	printf("sum is:%d\n", sum);
}

int main()
{
	static int a = 1;
	static int b = 0;
	int x = 1;
	func(a + b + x);
	return 0;
}

  • ELF头

    • gcc -c编译后产生main.o文件然后使用readelf -h main.o查看ELF

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4nPeons2-1684661656491)(E:\csdn_blog博客\大三\上\计算机系统二\image\elf头.png)]

前十六个字节的含义

  • 7f 45 4c 46前四个字节被称为ELF文件的魔数

    • 分别与ascll码中的DEL控制符、字符E、字符L、字符F对应
    • 魔数就是用来确认文件类型的
  • 02 01 01

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJRap49R-1684661656492)(E:\csdn_blog博客\大三\上\计算机系统二\image\magic.png)]
  • 最后9个字节ELF的标准中没有定义,用0填充

推测elf的大小

  • 本头的大小可以推出sections的起始地址,这里就是0x40

  • 推测整个elf文件的大小, 利用本头的大小和下图的三个信息

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lDpO3Lks-1684661656492)(E:\csdn_blog博客\大三\上\计算机系统二\image\elf文件大小推断.png)]

    • start of section headers:可以确定节头部表的起始位置

    • 节头大小节头数量可以确定节头表的大小

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xjhxQGwj-1684661656492)(E:\csdn_blog博客\大三\上\计算机系统二\image\1064.png)]

查看节头部表

readelf -S main.o:查看节头部表的信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IxFitNHp-1684661656492)(E:\csdn_blog博客\大三\上\计算机系统二\image\节头部表.png)]

推断每个sectionelf中的具体位置

  • 整个elf一共包含12section

  • offset代表每个section的起始位置

  • size每个section的大小

    • 例如.text这一section他的offset0x40,大小为0x54,由于elf头的大小为0x40,所以.text是紧跟在elf的后面的

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TYzrzzH5-1684661656493)(E:\csdn_blog博客\大三\上\计算机系统二\image\text.png)]

查看.text的内容

已知.text是存放已编译程序的机器代码

objdump -s -d main.o

  • -s:查看机器指令
  • -d:查看汇编代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HdVo2kcp-1684661656493)(E:\csdn_blog博客\大三\上\计算机系统二\复习\image\text机器代码.png)]

  • 前两个字节是指令地址
  • 后面的指令是机器指令
  • 每个指令对应的汇编代码可以在-d中查看

查看.data的内容

已知.data是存放已初始化的全局和静态C变量,而初始化为0的全局和静态变量被存在.bss

objdump -s -d main.o

  • 由于.text的起始位置是0x40,大小为0x56,故可以推断出下一个section的起始位置是0x94,查表可知.dataoffset0x94,刚好对应的上

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qukAji68-1684661656493)(E:\csdn_blog博客\大三\上\计算机系统二\image\data.png)]

  • 小端存储
  • 初始化为0b不会出现在此处

关于.bss

已知其是存放未初始化的静态C变量(未初始化的全局变量放在COMMON中)和初始化为0的全局和静态变量

  • 观察节头部表可以发现,.bss.rodata的起始位置一样但大小不一样

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4a4tHmsE-1684661656494)(E:\csdn_blog博客\大三\上\计算机系统二\image\bss.png)]

    • 这是因为bss不占据实际的空间,他就是一个占位符,程序区分已初始化和未初始化的变量是为了节省空间,当程序运行是,会在内存中分配这些变量,并把初始值设为0

查看.rodata的内容

  • ro就是read only,代表只读,此区域就是存放只读数据的,例如printf语句中的格式串,或者是switch的跳转表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-baSsGYAK-1684661656494)(E:\csdn_blog博客\大三\上\计算机系统二\复习\image\rodata.png)]

  • 0x73对应115(d)对应s的ascll

关于其他的节表示的信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EbTykcgB-1684661656495)(E:\csdn_blog博客\大三\上\计算机系统二\复习\image\其他节信息.png)]

详解符号表

typedef struct{
    int name;  // 符号的名称  通过在字符串表中的字节偏移中得到
    char type:4,  // 该符号的类别  函数还是变量 
    	binding:4;  // 全局还是本地
    char reserved;  // 没有被用到
    short section;  // 符号所属目标文件的节
    long value;  // 符号的地址相对于所属节起始位置的偏移
    long size;	// 符号的大小
} Elf64_Symbol;
  • 符号是链接的粘合剂,整个链接过程是基于符号才能正确完成

readelf -s main.o

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OL5GoBVk-1684661656495)(E:\csdn_blog博客\大三\上\计算机系统二\复习\image\symtab.png)]

  • Ndx对应section,代表符号所属目标文件的节
    • Ndx的取值还有三个,他们分别是ABS、UNDEF、COMMON,他们被统称为伪节,他们在节头部表中没有条目。只有可重定位目标文件才有这些伪节,可执行目标文件中没有
      • ABS:不该被重定位的符号
      • UNDEF:未定义的符号,但是在其他文件有定义
      • COMMON:还未被分配位置的未初始化的数据目标,也就是未初始化的全局变量会存放于此
  • Value代表符号的地址相对于所属节起始位置的偏移
    • 例如func符号,属于.text节,value0x00,大小为36

符号

  • 全局符号

  • 外部符号

    • 本文件引用外部文件的变量
  • 局部符号

    • static是局部符号

编译器如何解析多重定义的全局符号

强弱符号的概念

  • 函数已初始化的全局变量强符号
  • 未初始化的全局变量弱符号

处理多重定义的符号名

  • 规则一:不允许有多个同名符号
  • 规则二:如果有一个强符号多个若符号同名,那么选择强符号
  • 规则三:如果有多个弱符号同名,那么从这些弱符号中任意选择一个

对于这样一种情况:如果重复定义的符号是不同类型时,往往会破坏其他符号的内存

// foo1.cpp
#include<stdio.h>
void f();
int x = 15212;
int y = 15213;

int main()
{
    f();
    printf("x = 0x%x y = 0x%x \n", x, y);
    return 0;
}

// foo2.cpp
double x;
void f(){
    x = -0.0;
}
  • foo1xy的地址是连续的,被定义被int,占4个字节,但是在bar中,xdouble类型,占8个字节,在bar中对x赋值会影响y的值

静态库与静态链接

静态库:可以将多个相关的目标模块打包成一个单独的文件,称为静态库

  • 通过静态库,相关的函数可以被编译为独立的目标模块,然后封装成一个单独的静态库文件

  • 静态库可以用作链接器的输入。链接器在构造可执行文件时,从静态库中复制被应用程序引用的目标模块,其他未用到的模块则不会复制

  • 静态库的实例:

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tZQTRlAS-1684661656495)(E:\csdn_blog博客\大三\上\计算机系统二\复习\image\构造静态库.png)]

    • // main2.c
      #include <stdio.h>
      #include "vector.h"
      
      int x[2] = {1, 2};
      int y[2] = {3, 4};
      int z[2];
      
      int main() 
      {
          addvec(x, y, z, 2);
          printf("z = [%d %d]\n", z[0], z[1]);
          return 0;
      }
      
      // vector.h  其中的函数定义都在打包后的静态库中
      void addvec(int *x, int *y, int *z, int n);
      void multvec(int *x, int *y, int *z, int n);
      int getcount();
      

构造和使用一个静态库

  • > gcc -c addvec.c multvec.c  # 将想要打包的函数定义变成可重定位目标文件
    > ar rcs libvector.a addvec.o mutvec.o  # 打包成静态库
    > gcc -c main2.c   
    > gcc -static -o prog main2.o ./libvector.a  # 与静态库链接(使用静态库)
    
  • 总结:

    • 静态库就是各种可重定位文件的集合
    • 静态链接链接一个静态库的时候会按需链接

静态库的解析过程

  • 当在命令行输入以下命令来让程序使用静态库时

    gcc -static -o prog2c main2.o ./libvector.a

    链接器从左到右按照他们在编译器驱动程序命令行上出现的顺序来扫描可重定位目标文件存档文件,这会导致一些问题,最后来说。

  • 在链接器的扫描过程中,链接器维护三个集合

    • 可重定位目标文件的集合E(这个集合中的文件会被合并起来形成可执行文件)
    • 未解析的符号集合U(就是引用了但是没有定义,链接器会把他当做在其他文件定义)
    • 在前面的输入文件以及定义的符号集合D
  • 模拟解析过程

    • 第一个扫描的文件是main2.o,观察源程序可知,main.o会被放进集合E中,U中会增加main2.o中调用的addvecprintfD中会增加已定义的函数main和变量x、y、z

    • 第二个扫描的文件是libvector.a,根据其后缀,可知其为一个静态库,此时链接器就会尝试在U集合中寻找是否有与静态库同名的变量或函数,由于U中有addvec,故匹配,删除U集合中的addvec,将addvec.o放入E集合中,然后将addvec.o中定义的符号放进符号D

    • libvector.a中包含的所有目标文件要执行上述操作

    • 任何不包含在集合E中的成员目标文件都被简单的丢弃

  • 未定义的原因

    • 如果在最后一个目标文件读取完成之后,U集合不为空,则会产生未定义的情况。
  • 该算法的缺陷

    • 由于链接器是按照顺序从前往后的,故如果此指令gcc -static -o prog2c main2.o ./libvector.amain与静态库调换顺序,当扫描静态库时U集合并没有元素,故main扫描后U中符号无法消除就会产生未定义的情况
  • 互相依赖的命令

    • foo.c调用libx.alibx.a调用liby.a,然后liby.a又调用libx.a

      gcc -static foo.c libx.a liby.a libx.a

重定位

重定位节(section)和重定位符号定义

  • 对于main.osum.o,他们相同类型的section会被合并为一个新的section
  • 观察main.osum.o的符号表,他们的.text section都是从0开始的
  • 64linux系统中,ELF可执行文件默认从地址0x400000处开始分配,人们

重定位节中的符号引用

  • 本步骤是确定那些调用外部函数的目的地址(就是指令编码后面的的字节,汇编器把他们都填充成0,由链接器来赋值)

  • 链接器要依赖可重定位条目的数据结构来决定目的地址的值

  • 当编译器遇到最终位置不确定的符号引用时,他就产生一个重定位条目

    typedef struct{
        long offset;    //需要被修改的引用的节偏移(即该符号引用距离所在节的初始位置的偏移)。
        long type:32,   //重定位类型,不同的重定位类型会用不同的方式来修改引用
             symbol:32; //指向的符号,比如sum
        long addend;    //一个有符号常数,一些类型的重定位要使用它对被修改引用的值做偏移调整  pc相对寻址中默认是-4  绝对寻址默认是 0   
    }
    

    关于type字段,只学习两种即可,

    • R_X86_64_PC32PC相对地址

    • R_X86_64_32:绝对地址

  • 给出重定位之后的汇编代码,解释

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FsvAa8ll-1684661656496)(E:\csdn_blog博客\大三\上\计算机系统二\复习\image\重定位后.png)]

    当执行到call指令时,PC0x4004e3,目标地址就是PC地址加0x00000005,这个5就是链接器通过重定位条目所计算出来的

    如何计算的?

    // 对于这样两个函数
    // main.c
    int sum(int *a, int n);
    
    int array[2] = {1, 2};
    
    int main(){
        int val = sum(array, 2);
        return val;
    }
    
    // sum.c
    int sum(int * a, int n){
        int i, s = 0;
        
        for(i = 0; i < n; i++){
            s += a[i];
        }
        return s;
    }
    
    
    // 已经确定重定位后的.text节和sum函数的绝对地址分别为 0x4004d0 和 0x4004e8	`
    
    // 重定位之前的汇编代码(在合成之前main.o或者sum.o的.text起始地址都是0)
    000000000000<main>:
    0:  48 83 ec 08			sub $0x8, %rsp
    4:  be 02 00 00 00		mov $0x2, %esi
    9:  bf 00 00 00 00		moV $0×0, %edi
    e:  e8 00 00 00 00 		callq 13 <main+13>
    13: 48 83 c4 08			add $0x8, %rsp
    17: c3					retq
    
    // call后的目标位置值为f,表示与所在节的初始位置的偏移值为f,所以计算  目标位置的值为  sum - addend - (main + offset)
        			 0x4004e8 - 4 - (0x4004d0 + f) = 0x5
    
    // 所以
    e:  e8 00 00 00 00 		callq 13 <main+13>
    // 变为
    e:  e8 05 00 00 00      callq 4004e8 <sum>
    

可执行目标文件

可执行目标文件是一个二进制文件

  • 可执行目标文件的格式与可重定位目标文件的格式类似

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LY8kgsJQ-1684661656496)(E:\csdn_blog博客\大三\上\计算机系统二\复习\image\可执行目标文件.png)]

    • ELF头部描述文件的总体格式,还包括程序的入口点也就是当程序运行时要执行的第一条地址
    • .init节定义了一个小函数,叫做_init,程序的初始化代码会调用它

加载可执行目标文件

  • 任何Linux程序都可以通过调用execve函数来调用加载器。加载器将可执行文件的代码和数据从磁盘复制到内存中,然后通过跳转到程序的第一条指令或入口来运行该程序。这个将程序复制到内存并运行的过程叫做加载

  • 每个Linux程序都有一个运行时内存映像,内存映像如图所示

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o1mtvH9q-1684661656497)(E:\csdn_blog博客\大三\上\计算机系统二\复习\image\内存映像.png)]

    • Linux x86-64系统中,代码段总是从地址0x400000处开始后面是数据段,
    • 运行时堆在数据段之后,通过调用malloc库往上增长
    • 堆后的区域是为共享模块保留的
    • 用户栈总是从最大的合法用户地址(248 - 1)开始,向小内存地址增长。
    • 内核就是操作系统驻留在内存的部分
    • 注意:
      • 为了简洁,将代码段与数据段挨在了一起,事实上,.data段是有对齐要求的。所以代码段和数据段之间是有间隙的。
      • 同时,在分配栈、共享库和堆段运行时地址时,链接器还会使用地址空间布局随机化。但是他们的相对位置不会变

加载运行过程细节

  • 当加载器运行时,在程序头部表的引导下,加载器将可执行文件的片复制到代码段和数据段。

  • 然后,加载器跳转到程序的入口点(_start函数的地址),这个函数是在系统目标文件ctrl.o中定义的

  • start函数调用系统启动函数 _ _libc_start_main,该函数定义在libc.so中。

  • 上一函数初始化执行环境,调用用户层的main函数,再由

    _ _libc_start_main处理main函数的返回值,并且它在需要的时候返回给内核

共享库

是一种特殊的可重定位目标~文件

构造一个共享库

> gcc -shared -fpic -o libvector.so addvec.c mulvec.c
  • -fpic:告诉编译器生成与位置无关的代码

使用共享库

> gcc -o prog main.c ./libvector.so

解释共享库工作原理

  • 当创建可执行文件时,静态执行一些链接,然后在程序加载时,动态完成链接过程。
  • 没有任何libvector.so的代码和数据节真的被复制到可执行文件prog中,-> 链接器复制了一些重定位和符号表信息,他们使得运行时可以解析对libvector.so中代码和数据的引用
  • 当可执行程序prog被加载运行时,加载器会发现prog中存在一个名为.interpsection,这个section包含了动态链接器的路径名,这个动态链接器本身也是一个共享目标文件
  • 接下来,加载器会将这个动态链接器加载到内存中运行,然后由动态链接器执行重定位代码和数据的工作
    • 重定位libc.so的文本和数据到某个内存段
    • 重定位libvecor.so的文本和数据到另一个内存段
    • 重定位prog中所有由libc.solibvector.so定义的符号的引用
  • 之后共享库的位置就固定了,并且在程序执行的过程中都不会改变

文章参考与<零声教育>的C/C++linux服务期高级架构系统教程学习

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

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

相关文章

seata的部署和集成

seata的部署和集成 一、部署Seata的tc-server 1.下载 首先我们要下载seata-server包&#xff0c;地址在http://seata.io/zh-cn/blog/download.html 2.解压 在非中文目录解压缩这个zip包&#xff0c;其目录结构如下&#xff1a; 3.修改配置 修改conf目录下的registry.conf文…

开源大模型资料总结

基本只关注开源大模型资料&#xff0c;非开源就不关注了&#xff0c;意义也不大。 基座大模型&#xff1a; LLaMA&#xff1a;7/13/33/65B&#xff0c;1.4T token LLaMA及其子孙模型概述 - 知乎 GLM&#xff1a;6/130B&#xff0c; ChatGLM基座&#xff1a;GLM&#xff08…

【网络】- TCP/IP四层(五层)协议 - 网际层(网络层) - 网际协议IP

目录 一、概述 二、初步了解网际协议 IP  &#x1f449;2.1 与数据链路层的区别  &#x1f449;2.2 网际协议 IP 概览  &#x1f449;2.3 分层的意义 三、IP协议基础知识  &#x1f449;3.1 IP地址属于网络层地址  &#x1f449;3.2 路由控制  &#x1f449;3.3 IP分包与…

solr快速上手:核心概念及solr-admin界面介绍(二)

0. 引言 上一节&#xff0c;我们简单介绍了solr并演示了单节点solr的安装流程&#xff0c;本章&#xff0c;我们继续讲解solr的核心概念 solr快速上手&#xff1a;solr简介及安装&#xff08;一&#xff09; 1. 核心概念 核心&#xff08;索引/表&#xff09; 在es中有索引…

【软件测试】5年测试老鸟总结,自动化测试成功实施,你应该知道的...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 自动化测试 Pytho…

基于html+css的图展示82

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

chatgpt赋能Python-pythonage

Pythonage - 一款优秀的Python SEO工具 无论是个人博客还是商业网站&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;都是最重要的。Pythonage是一款优秀的Python SEO工具&#xff0c;可以帮助你优化你的网站并提高搜索引擎排名。在这篇文章中&#xff0c;我们将详细介绍…

ChatGPT 使用 拓展资料:开始构建你的优质Prompt

ChatGPT 使用 拓展资料:开始构建你的优质Prompt

【JavaEE】阻塞队列、定时器和线程池

目录 1、阻塞队列 1.1、概念 1.2、生产者消费者模型 1.3、阻塞队列的模拟实现 2、定时器 2.1、使用标准库中的定时器 2.2、模拟实现定时器 3、线程池 3.1、标准库中的线程池 3.1.1、ThreadPoolExecutor类的构造方法 3.1.2、Java标准库的4种拒绝策略【经典面试题】…

Canal内存队列的设计

1、背景 笔者的公司内部使用了开源的Canal数据库中间件来接受binlog数据&#xff0c;并基于此进行数据的订阅和同步到各种同构和异构的数据源上&#xff0c;本文将对Canal内部使用的store模块进行分析。 2、Store模块概览 Canal的store模块用于存储binlog中的每一个event&am…

MySQL- 多表查询(上)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️树高千尺&#xff0c;落叶归根人生不易&…

安卓基础巩固(一):布局、组件、动画、Activity、Fragment

文章目录 布局LinearLayoutRelativeLayoutTableLayoutFrameLayoutConstraintLayoutListView基于ArrayAdapter自定义Adaper提升ListView的运行效率 RecyclerView基本属性使用案例布局&#xff08;显示方式&#xff09;监听事件利用View.onClickListener 和 onLongClickListener …

日志收集机制和日志处理流程规范

本博客地址&#xff1a;https://security.blog.csdn.net/article/details/130792958 一、日志收集与处理流程 云原生平台中对日志提取收集以及分析处理的流程与传统日志处理模式大致是一样的&#xff0c;包括收集、ETL、索引、存储、检索、关联、可视化、分析、报告这9个步骤…

Leetcode 二叉树详解

二叉树 树的概念及基本术语见树与二叉树的基础知识 定义&#xff1a;一棵二叉树是结点的一个有限集合&#xff0c;该集合或者为空&#xff0c;或者是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的二叉树组成。 特点&#xff1a;每个结点至多只有两棵子树&#xff…

Vivado综合属性系列之八 DIRECT_ENABLE DIRECT_RESET

目录 一、前言 二、DIRECT_ENABLE、DIRECT_RESET ​ ​2.1 属性说明 ​ ​2.2 工程代码 ​ ​2.3 综合结果 一、前言 在Vivado 2019之前的版本中&#xff0c;对于设计中触发器的使能端口和复位端口是会自动接地&#xff0c;如果需要接设计端口&#xff0c;如果要直连…

GitHub Copilot开发者酷游网址训练营

目标读者 已使用且【酷游网K͜W͜98典neт娜娜宝宝提供】想发挥GitHub Copilot所有潜能的使用者想知道GitHub Copilot未来展望的使用者想了解GitHub Copilot能力的开发者 简介 最近Open AI带起的新世代&#xff0c;热潮汹涌&#xff0c;一堆AI工具蜂拥而至(如:chatGPT和Midjo…

近期关于Transformer结构有潜力的改进方法总结

目录 0 引言1 Gated Linear Unit (GLU)1.1 思路 2 Gated Attention Unit (GAU)2.1 思路2.2 实验结论2.3 混合注意力 3 FlashAttention3.1 标准Attention的实现3.2 FlashAttention的实现针对目标1针对目标2 4 总结5 参考资料 0 引言 标准Transformer在最新的实际大模型中并没有…

C++STL算法篇之集合算法

CSTL算法篇之集合算法 集合算法set_union(并集)set_difference(差集)set_intersection(交集)set_symmetric_difference(对称差集) 集合算法 当然最好还是要包含 functional algorithm 这2个头文件 集合算法有4个函数 1.set_union 交集 2.set_difference 差集 3.set_intersectio…

安卓开发多选列表和回显已选择内容

问题背景 安卓日常开发和学习过程中&#xff0c;经常会碰到需要多选列表和显示已选择内容的场景&#xff0c;本文将介绍安卓实现多选列表和回显已选择内容的一种方案。 问题分析 话不多说&#xff0c;先上效果&#xff1a; 思路分析&#xff1a; 一个纵向列表显示待选择内…

多线程基础(二)CAS无锁优化/自旋锁/乐观锁、ABA问题

CAS &#xff08;Compare And Set&#xff09;比较并替换 上篇文章的锁问题解决&#xff0c;可以使用更高效的方法&#xff0c;使用AtomXXX类&#xff0c;AtomXXX类本身方法都是原子性的&#xff0c;但不能保证多个方法连续调用是原于性的。 import java.util.ArrayList; imp…