【程序员的自我修养03】深入了解ELF文件格式

绪论

        大家好,欢迎来到【程序员的自我修养】专栏。正如其专栏名,本专栏主要分享学习《程序员的自我修养——链接、装载与库》的知识点以及结合自己的工作经验以及思考。编译原理相关知识本身就比较有难度,我会尽自己最大的努力,争取深入浅出。若你希望与一群志同道合的朋友一起学习,也希望加入到我们的学习群中。文末有加入方式。

简介

        从上文【程序员的自我修养02】初识ELF文件格式-CSDN博客中,我们已经初步了解ELF文件布局,其中应该有文件头、代码段、数据段、.bss段、段表等。本文我们从段表开始,进一步了解ELF文件的布局。请耐心看完,我也会分享一些不常用,但是很有趣的小技巧。

.section tables

我们可通过readelf -S example.o命令查看段表信息。如下:

yihua@ubuntu:~/test/example$ readelf -S example.o
There are 13 section headers, starting at offset 0x450:Section Headers:[Nr] Name              Type             Address           Offset   Size              EntSize          Flags  Link  Info  Align[ 0]                   NULL             0000000000000000  00000000 0000000000000000  0000000000000000           0     0     0[ 1] .text             PROGBITS         0000000000000000  00000040 0000000000000059  0000000000000000  AX       0     0     1[ 2] .rela.text        RELA             0000000000000000  00000340 0000000000000078  0000000000000018   I      10     1     8[ 3] .data             PROGBITS         0000000000000000  0000009c 0000000000000008  0000000000000000  WA       0     0     4[ 4] .bss              NOBITS           0000000000000000  000000a4 0000000000000004  0000000000000000  WA       0     0     4[ 5] .rodata           PROGBITS         0000000000000000  000000a4 0000000000000004  0000000000000000   A       0     0     1[ 6] .comment          PROGBITS         0000000000000000  000000a8 000000000000002a  0000000000000001  MS       0     0     1[ 7] .note.GNU-stack   PROGBITS         0000000000000000  000000d2 0000000000000000  0000000000000000           0     0     1[ 8] .eh_frame         PROGBITS         0000000000000000  000000d8 0000000000000058  0000000000000000   A       0     0     8[ 9] .rela.eh_frame    RELA             0000000000000000  000003b8 0000000000000030  0000000000000018   I      10     8     8[10] .symtab           SYMTAB           0000000000000000  00000130 0000000000000198  0000000000000018          11    11     8[11] .strtab           STRTAB           0000000000000000  000002c8 0000000000000075  0000000000000000           0     0     1[12] .shstrtab         STRTAB           0000000000000000  000003e8 0000000000000061  0000000000000000           0     0     1

 

由上分析:

        由第一句可知,本段表共有13个段,并在文件中offset 0x450 处开始,这与上一章中文件头内容是匹配上的。(0x450是1104的的16进制)。

我们先看一下表的列项:

  • Name :表示段名称。可知ELF文件中不仅仅包含.text、.data、.bss,还有其它内容。
  • Type : 表示段的类型。因为链接器并不是通过段名称确定段类型的。比如.text段就一定是代码段吗?常见的段类型有:

        PROGBITS:程序段。代码段和数据段都是这种类型。

        SYMTAB:符号表内容。也就是我们nm命令查看的内容。

        STRTAB:表示该段的内容为字符串表

        RELA:重定位表。该段包含了重定位信息。在下个章节静态链接阶段我们会再讨论。

        HASH:符号的哈希表。

        DYNAMIC:动态链接信息。

        NOBITS:表示该段没有内容比如.bss段。如上所示,.bss和.rodata段的偏移是一样的。

        REL:该段包含重定位信息。在下个章节静态链接阶段我们会再讨论

        DNYSYM:动态链接的符号表。

  • Address: 段虚拟地址。即程序加载时,该段要加载到虚拟内存的地址。这是一个很关键的知识点:代码的虚拟地址在编译阶段就已经确定了,并不是运行时由系统决定的。gdb调试时,定位动态库的调试信息,就是依赖于该点。

    但是为什么上述为NULL呢?

    因为example.o是可重定位文件,虚拟机地址还未确认,只有可执行文件各端的虚拟地址是确认的,如下:

yihua@ubuntu:~/test/example$ readelf -S example
There are 29 section headers, starting at offset 0x19f8:
Section Headers:[Nr] Name              Type             Address           Offset    Size              EntSize          Flags  Link  Info  Align[ 0]                   NULL             0000000000000000  00000000  0000000000000000  0000000000000000           0     0     0[ 1] .interp           PROGBITS         0000000000000238  00000238  000000000000001c  0000000000000000   A       0     0     1[ 2] .note.ABI-tag     NOTE             0000000000000254  00000254  0000000000000020  0000000000000000   A       0     0     4[ 3] .note.gnu.build-i NOTE             0000000000000274  00000274  0000000000000024  0000000000000000   A       0     0     4[ 4] .gnu.hash         GNU_HASH         0000000000000298  00000298  000000000000001c  0000000000000000   A       5     0     8[ 5] .dynsym           DYNSYM           00000000000002b8  000002b8  00000000000000a8  0000000000000018   A       6     1     8[ 6] .dynstr           STRTAB           0000000000000360  00000360  0000000000000084  0000000000000000   A       0     0     1[ 7] .gnu.version      VERSYM           00000000000003e4  000003e4  000000000000000e  0000000000000002   A       5     0     2[ 8] .gnu.version_r    VERNEED          00000000000003f8  000003f8  0000000000000020  0000000000000000   A       6     1     8

 

  • Offset: 该段位于文件中的偏移注:.bss 段的该参数就没有意义,因为它并不存在于文件中
  • Size:该段内容长度。
  • EntSize: 项的长度。有些段包含了一些大小固定的项,比如符号表,它包含的每个符号所占的大小都是一样的。对于这种段,EntSize 表示每个项的大小。如果为0,则表示该段不包含固定大小的项。
  • Flags:段的标志位。该标志位决定该段在进程虚拟地址的属性。我们一般只要关注:

【A】表示该段在进程空间中必须分配空间。比如代码段,数据段,.bss段一定会有该标识。但是符号表,调试信息则不需要。

【W】表示该段在进程空间中可写。比如.bss 和数据段。而代码段是不可写的。

【X】表示该段在进程空间中可被执行。一般指代码段。

  • Link 和 Info:表示段的链接信息。
  • Align:表示该段对地址对其的要求。

        通过对段表的了解,我们现在对example.o的内容布局更详细了,如下:

        其中空白内容,则是因为各段有字节对齐要求,进行了对齐。而其它部分的内容暂不关注,一般就是调试信息等。

        综上所述,我们基本已经了解了ELF文件格式的布局,接下来,我们尝试深入了解各个段的内容。

.text

        我们可以通过objdump -s -d example.o查看目标文件的代码段。其中-s表示将所有段的内容以十六进制输出,-d表示将所有包含指令的段反汇编。输出如下:

yihua@ubuntu:~/test/example$ objdump -s -d example.o
example.o:     file format elf64-x86-64
Contents of section .text:
 0000 554889e5 4883ec10 897dfc8b 45fc89c6  UH..H....}..E...
 0010 488d3d00 000000b8 00000000 e8000000  H.=.............
 0020 0090c9c3 554889e5 4883ec10 c745f801  ....UH..H....E..
 0030 0000008b 15000000 008b0500 00000001  ................
 0040 c28b45f8 01c28b45 fc01d089 c7e80000  ..E....E........
 0050 0000b800 000000c9 c3                 .........
Contents of section .data:
 0000 54000000 55000000                    T...U...
Contents of section .rodata:
 0000 25640a00                             %d..
Contents of section .comment:
 0000 00474343 3a202855 62756e74 7520372e  .GCC: (Ubuntu 7.
 0010 352e302d 33756275 6e747531 7e31382e  5.0-3ubuntu1~18.
 0020 30342920 372e352e 3000               04) 7.5.0.
Contents of section .eh_frame:
 0000 14000000 00000000 017a5200 01781001  .........zR..x..
 0010 1b0c0708 90010000 1c000000 1c000000  ................
 0020 00000000 24000000 00410e10 8602430d  ....$....A....C.
 0030 065f0c07 08000000 1c000000 3c000000  ._..........<...
 0040 00000000 35000000 00410e10 8602430d  ....5....A....C.
 0050 06700c07 08000000                    .p......

Disassembly of section .text:

0000000000000000 <func1>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 10             sub    $0x10,%rsp
   8:   89 7d fc                mov    %edi,-0x4(%rbp)
   b:   8b 45 fc                mov    -0x4(%rbp),%eax
   e:   89 c6                   mov    %eax,%esi
  10:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi        # 17 <func1+0x17>
  17:   b8 00 00 00 00          mov    $0x0,%eax
  1c:   e8 00 00 00 00          callq  21 <func1+0x21>
  21:   90                      nop
  22:   c9                      leaveq
  23:   c3                      retq

0000000000000024 <main>:
  24:   55                      push   %rbp
  25:   48 89 e5                mov    %rsp,%rbp
  28:   48 83 ec 10             sub    $0x10,%rsp
  2c:   c7 45 f8 01 00 00 00    movl   $0x1,-0x8(%rbp)
  33:   8b 15 00 00 00 00       mov    0x0(%rip),%edx        # 39 <main+0x15>
  39:   8b 05 00 00 00 00       mov    0x0(%rip),%eax        # 3f <main+0x1b>
  3f:   01 c2                   add    %eax,%edx
  41:   8b 45 f8                mov    -0x8(%rbp),%eax
  44:   01 c2                   add    %eax,%edx
  46:   8b 45 fc                mov    -0x4(%rbp),%eax
  49:   01 d0                   add    %edx,%eax
  4b:   89 c7                   mov    %eax,%edi
  4d:   e8 00 00 00 00          callq  52 <main+0x2e>
  52:   b8 00 00 00 00          mov    $0x0,%eax
  57:   c9                      leaveq
  58:   c3                      retq

如上所示:

        绿色字体:用16进制打印了.text、.data、.rodata、.comment、.eh_frame段的信息,其长度与段表中显示的长度是一一对应的。

        黄色字体:则是代码段经过反汇编的内容。

        正常情况下,我们一般是不需要关注代码的汇编层面的。但是当遇到一些棘手问题时,特别是踩内存导致得到异常情况,我们就有可能需要分析程序的汇编语句了。我曾经遇到的一个案例。大致问题原因如下:

        客户的提供的第三方代码出现了踩内存问题,修改了上层栈内容。导致调用客户接口之后,在回到我的接口后,执行打印语句,类似:printf("hello world\n");就会crash。这个问题困扰了客户,和同事很长时间。

我的排查思路,大致如下:

  1. 通过gdb 查看crash 堆栈信息,发现入参hello world是一个非法地址。
  2. 通过反汇编,查看相应代码段的入参保存在哪个寄存器,以及这个寄存器由哪里赋值而来。
  3. 最终再结合gdb watch指令,一点点逆向排查,确定了是客户提供的sdk 操作了 其它函数栈里面的内容(越界)。

注:"有时候"我们通过虚拟机里面的objdump 指令,并不能反汇编目标平台的程序。那是因为代码段是二进制代码,不同平台是不一样的。因而非x86平台的程序,虚拟机是无法解析的。需要使用交叉编译工具链中对应的调试工具

.data & .rodata

        我们知道.data 段保存的是那些已经初始化了的全局变量和局部静态变量.rodata 段保存的是只读数据,一般是程序里面的只读变量(const 修饰的变量)和字符串常量。但是真是如此吗?我们不妨进一步验证以下。

        我们由段表可知:.data段的起始地址是0x9c,且长度 8字节; .rodata 段的起始地址0xa4,且长度是4。我们尝试用二进制文本编辑器查看example.o文件。如下:

        结合上篇文章中描述的该可重定位文件是小端字节序。因此这两个值就分别对应0x54和0x55。转为十进制,就正好对应int global_init_var = 84;static int static_var = 85;。是不是很惊喜~~

.rodata段的内容如下:

        可知.rodata起始保存的就是我们printf接口中的字符串常量"%d\n",字符串默认结尾有\0。

tips:

        我既然我们已经知道数据在example.o的具体位置,如果我们通过二进制编辑器修改这个值,是否能达到修改最终的输出结果呢?于是尝试如下:

        最终结果如我们所想,的确可以通过该方式简单修改程序的逻辑。但是在实际工作场景中,如何应用起来,我还不清楚。暂且当作一个小技巧吧。

.bss

        .bss段用于存放为未初始化的全局变量和局部静态变量。如演示代码所示,int global_unint_var;static int static_var2;两变量应该保存在该段中。根据段表信息

Section Headers:[Nr] Name              Type             Address           Offset   Size              EntSize          Flags  Link  Info  Align[ 4] .bss              NOBITS           0000000000000000  000000a4 0000000000000004  0000000000000000  WA       0     0     4[ 5] .rodata           PROGBITS         0000000000000000  000000a4 0000000000000004  0000000000000000   A       0     0     1

我有两个疑问:

一、 为什么global_unint_var 和 static_var2两个变量应该占用8个字节,但是.bss 段的Size 只有4Byte?

二、为什么.bss 段和 .rodata段的起始地址都一样?也就是.bss 为什么不存在于文件?

        第一个问题,先不做回答,后面.symtab 小节再讨论。对于问题二,我的理解如下:

        我们知道,未初始化的全局变量和局部静态变量的值默认初始化为0,那么即没有必要在ELF文件中体现。只需要告诉操作系统,bss 段占用4字节,当程序加载时,自然会在虚拟空间中分配对应内存给bss。这样就达到节省磁盘的目的。(注:没有节省内存),那么这4字节表示哪个变量呢?请继续往下看。

.rel.text

        .rel.text 段的类型是REL,也就是说它是一个重定位表。

        我们知道链接器在处理目标文件时,需要对目标文件中某些部位进行重定位,即代码段和数据段中哪些绝对地址的引用需要修改。.ral.text 则是对.text段的重定位表;.rel.data 则是对.data段的重定位表。

        我们可以通过readelf -r example.o查看文件的重定位表,内容如下:

yihua@ubuntu:~/test/example$ readelf -r example.o

Relocation section '.rela.text' at offset 0x340 contains 5 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000013  000500000002 R_X86_64_PC32     0000000000000000 .rodata - 4
00000000001d  000f00000004 R_X86_64_PLT32    0000000000000000 printf - 4
000000000035  000300000002 R_X86_64_PC32     0000000000000000 .data + 0
00000000003b  000400000002 R_X86_64_PC32     0000000000000000 .bss - 4
00000000004e  000d00000002 R_X86_64_PC32     0000000000000000 func1 - 4

Relocation section '.rela.eh_frame' at offset 0x3b8 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000020  000200000002 R_X86_64_PC32     0000000000000000 .text + 0
000000000040  000200000002 R_X86_64_PC32     0000000000000000 .text + 24
 

        关于如何理解这些信息,我们再后续静态链接章节描述。大家可以先知道有这个东西,留个印象。

.symtab

        我们知道不同文件间对函数、变量之间的引用,其实就是对符号的引用。链接的过程,其实质就是通过符号将不同的目标文件相互“粘”到一起。因此符号对于一个目标文件就显得是什么重要。

        我们可以通过readelf -s example.o查看文件的符号表。如下:

yihua@ubuntu:~/test/example$ readelf -s example.o

Symbol table '.symtab' contains 17 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS example.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5
     6: 0000000000000004     4 OBJECT  LOCAL  DEFAULT    3 static_var.1801
     7: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    4 static_var2.1802
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    7
     9: 0000000000000000     0 SECTION LOCAL  DEFAULT    8
    10: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
    11: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 global_init_var
    12: 0000000000000004     4 OBJECT  GLOBAL DEFAULT  COM global_unint_var
    13: 0000000000000000    36 FUNC    GLOBAL DEFAULT    1 func1
    14: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
    15: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND printf
    16: 0000000000000024    53 FUNC    GLOBAL DEFAULT    1 main

  • Value:符号相对应的值。这个值的含义与符号相关,不同的符号表示的含义不同。规则如下:
  • 在目标文件中,如果是符号的定义,并且不是“COM”类型,表示该符号在段中的偏移。比如static_var2.1802符号,则在.bss段的起始地址。同时也回到了上面提到的问题:.bss段保存的是哪一个变量
  • 在目标文件中,如果符号是“COM”类型,则表示对其的类型。比如:global_unint_var符号,要求4字节对其。
  • 在可执行文件中,则表示进程空间的虚拟地址
  • Size:符号大小。
  • Type:符号类型。【NOTYPE】表示该符号是未知的类型、【OBJECT】表示该符号是个数据类型、【SECTION】表示该符号是一个段、【FUNC】表示该符号是函数、【FILE】表示该符号是文件名。
  • Bind:符号绑定信息。【LOCAL】局部符号,对于目标文件外不可见。【GLOBAL】全局符号,对外部可见。【WEAK】弱引用。可参考C语言中弱符号与弱引用的实际应用_c接口声明位弱符号_谢艺华的博客-CSDN博客。可通过该标识,判断客户提供的SDK,是否对外提供了对应接口。
  • Ndx:符号所在的段。如果符号在本目标文件中,那么数字则表示所在的段处于段表中的下标。结合readelf -S 查看。比如3 static_var.1801 则表示static_var.1801符号处于.data段。其也有特殊值:
  • ABS:表示该符号包含了一个绝对值。比如文件名的符号就属于该类型。
  • COM:一般情况下,为初始化的全局变量就是这个类型。比如:global_unint_var
  • UND:未定义的符号。表示该符号在本目标文件被引用到,但是定义在其它目标文件中。

        对于符号我们经常遇到的问题就是链接阶段符号未定义错误。undefined reference to `***。一般去找对应的源码件,查看是否编译或链接库即可。若即编译也链接了,大概率就是符号修饰问题了,可参考该文章深思:C与C++相互调用问题-CSDN博客

其它

        还有其它的段比如:dynamic、.symtab、.plt、.got、.init、.fini。我们在本文就不再详细介绍了,在后续的章节再逐一介绍。还请朋友们关注,不迷路哦~~~。

总结

        本文在上一篇的基础上,进一步了解了ELF的文件格式,了解其文件布局。

        之后再介绍常见的段,代码段,数据段,bss段,符号表等内容,以及工作中可以借鉴的地方。也初步了解到了重定位表的存在及含义,为后面的静态链接做好了铺垫。

        有任何相关问题欢迎留言讨论,我会尽快回复。

        若您正遇到相关问题,苦于没有一群志同道合的朋友交流,探讨。也欢迎加入我们的讨论组群。

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

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

相关文章

嵌入式Linux:ARM驱动+QT应用+OpenCV人脸识别项目实现

一、前言&#xff1a; 这个项目主要分为两部分&#xff0c;客户端&#xff08;ARM板端&#xff09;负责利用OpenCV采集人脸数据&#xff0c;利用TCP将人脸数据发送给服务器&#xff0c;然后服务器根据人脸数据进行人脸识别&#xff0c;将识别后的结果返还给客户端&#xff0c;客…

请大数据把奥威BI分析工具推给每一个财务!

这个财务指标怎么算&#xff1f;那些数据什么时候能拿到&#xff1f;看完报表&#xff0c;发现某部门上个月的支出涨幅过大&#xff0c;想了解原因怎么办&#xff1f;……财务人&#xff0c;你是不是每个月都把时间消耗在这些事情上了&#xff1f;那你可得快接住这个BI大数据分…

网站文章采集软件大盘点

在信息时代&#xff0c;随着互联网的不断发展和普及&#xff0c;获取、整理和利用海量信息成为各行业的共同挑战。在这个背景下&#xff0c;网站文章采集技术应运而生&#xff0c;成为满足信息需求的重要工具。本文将对网站文章采集及其相关软件进行深入探讨&#xff0c;为读者…

Golang语言基础之切片

概述 数组的长度是固定的并且数组长度属于类型的一部分&#xff0c;所以数组有很多的局限性 func arraySum(x [3]int) int{sum : 0for _, v : range x{sum sum v}return sum } 这个求和函数只能接受 [3]int 类型&#xff0c;其他的都不支持。 切片 切片&#xff08;Slic…

virustotal的使用

www.virustotal.com是一个恶意代码扫描网站&#xff0c;提交时需要验证码。 该网站有近百个病毒引擎的支持。 该网站最有用的地方在于&#xff0c;这是一个交互式的恶意代码检测网站&#xff0c;这样的模式有一个隐形的福利&#xff0c;那就是为病毒木马爱好者提供了攻防一体…

市面上这么多SD-WAN服务商,究竟有何不同?

随着数字化浪潮的不断发展&#xff0c;企业网络已经成为了现代企业中不可缺少的一部分。而提供企业组网服务的SD-WAN服务商也呈现出快速增长的趋势。但是&#xff0c;市场上有这么多SD-WAN服务商&#xff0c;各个服务商技术实现方案非常相似&#xff0c;那么这些服务商之间到底…

人工智能驱动的医疗辅助:陪诊系统的技术原理与应用

随着人工智能技术的不断发展&#xff0c;医疗领域也迎来了新的可能性。本文将深入探讨陪诊系统的技术原理及其在医疗领域中的应用。我们将重点关注人工智能的核心概念&#xff0c;如自然语言处理、机器学习和语音识别&#xff0c;以解释陪诊系统是如何在医疗环境中发挥作用的。…

html5各行各业官网模板源码下载(1)

文章目录 1.来源2.源码模板2.1 HTML5白色简洁设计师网站模板 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/134682321 html5各行各业官网模板源码下载&#xff0c;这个主题覆盖各行业的html官网模板&#xff0c;效果模…

图解Redis适用场景

Redis以其速度而闻名。 1 业务数据缓存 1.1 通用数据缓存 string&#xff0c;int&#xff0c;list&#xff0c;map。Redis 最常见的用例是缓存对象以加速 Web 应用程序。 此用例中&#xff0c;Redis 将频繁请求的数据存储在内存。允许 Web 服务器快速返回频繁访问的数据。这…

Make sure bypassing Vue built-in sanitization is safe here.

一、问题描述 二、问题分析 XSS(跨站脚本攻击) XSS攻击通常指的是通过利用网页开发时留下的漏洞&#xff0c;通过巧妙的方法注入恶意指令代码到网页&#xff0c;使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript&#xff0c;但实际上也可以包括J…

【注册表】Sublime Text添加到右键菜单

官网下载 windows下地地址: http://www.sublimetext.com/download_thanks?targetwin-x64设置右键菜单和菜单小图标 win R打开运行&#xff0c;并输入regedit打开注册表编辑器依次找到HKEY_CLASSESS_ROOT -> * -> Shell&#xff0c;下面新建项&#xff0c; 这个项的名…

【TinyALSA全解析(三)】tinyplay、tincap、pcm_open源码解析

tinyplay、tincap、pcm_open源码解析 一、本文的目的二、tinyplay.c源码分析三、tinycap.c源码分析四、pcm.c如何调度到Linux Kernel4.1 pcm_open解析4.1.1 pcm_open的主要流程4.1.2 流程说明4.1.3 调用方法 4.2 pcm_write解析 /*********************************************…

图解系列--HTTPS,认证

确保 Web 安全的HTTPS 1.HTTP 的缺点 1.1.通信使用明文可能会被窃听 加密处理防止被窃听 加密的对象可以有这么几个。 (1).通信的加密 HTTP 协议中没有加密机制&#xff0c;但可以通过和 SSL&#xff08;Secure Socket Layer&#xff0c;安全套接层&#xff09;或TLS&#xff…

猜-MISC-bugku-解题步骤

——CTF解题专栏—— 题目信息&#xff1a; 题目&#xff1a;猜 作者&#xff1a;harry 提示&#xff1a; 解题附件&#xff1a;flag格式key{图中人物名字全拼} 解题思路&#xff1a; 这......头都没有&#xff0c;让我guess&#xff1f;&#xff1f;&#xff1f;详细信息看…

NASM安装和结合nodepad++进行编译的过程

mov ax,0x30 mov bx,0xc0 add ax,bx times 502 db 0 db 0x55 db 0xAA nasm安装地址: https://www.nasm.us/ 下载exe安装 在命令行提示符输入nasm编译命令 nasm exam.asm -f bin -o exam.bin 此时输入回车将会执行编译过程。 1&#xff0c;启动NotePad&#xff0c;在菜单上选…

web前端tips:js继承——寄生组合式继承

上篇文章给大家分享了 js继承中的 寄生式继承 web前端tips&#xff1a;js继承——寄生式继承 今天给大家分享一下 js 继承中的 寄生组合式继承 寄生组合式继承 寄生组合式继承是一种结合了寄生式继承和组合式继承的方式&#xff0c;它的目标是减少组合式继承中多余的调用父…

【Java 并发编程】进程线程、lock、设计模式、线程池...

博主&#xff1a;_LJaXi Or 東方幻想郷 专栏&#xff1a; Java | 从入门到入坟 Java 并发编程 并发编程多线程的入门类和接口线程组和线程优先级线程的状态及主要转化方法线程间的通信重排序和 happens-beforevolatilesynchronized 与锁CAS 与原子操作AQS计划任务Stream 并行计…

开放式耳机哪个品牌好用?超好用的耳机推荐,新手小白必看

在当今数不胜数的音频品牌中&#xff0c;寻找一款优秀的开放式耳机成为了许多音乐爱好者和新手小白的共同关注点&#xff0c;开放式耳机以其通透的音质和舒适的佩戴感受受到了广泛好评&#xff0c;但市场上的选择却让人眼花缭乱&#xff0c; 为了帮助新手小白在这个耳机的海洋…

从零开始:打造自己的抖音核销工具小程序

对于商家而言&#xff0c;如何高效核销活动中的抖音优惠券成为一项挑战。在这篇文章中&#xff0c;我们将探讨如何从零开始&#xff0c;打造一个个性化、高效的抖音核销工具小程序。 第一步&#xff1a;明确需求和目标 在动手之前&#xff0c;我们需要明确自己的需求和目标。…

ICC2:使用analyze_lib_cell_placement检查lib cell的pass rate

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 在place之前需要使analyze_lib_cell_placement命令去检查lib cell在当前的site row/power plan/legalize设置的环境下能够正常place和legalize。 下面分享一个脚本去报告pass rate低于2%的lib cell…