将 binutils `size` 输出从 "sysv" 格式(`size --format=sysv my_executable`)转换为 "berkeley" 格式(`size --format=berkeley my_executable`)

Convert binutils `size` output from "sysv" format (`size --format=sysv my_executable`) to "berkeley" format (`size --format=berkeley my_executable`)

我想知道如何获得这种 berkeley 格式输出:

$ size --format=berkeley /bin/ls
   text    data     bss     dec     hex filename
 124042    4728    4832  133602   209e2 /bin/ls

从此sysv格式输出:

$ size --format=sysv /bin/ls
/bin/ls  :
section                size      addr
.interp                  28       568
.note.ABI-tag            32       596
.note.gnu.build-id       36       628
.gnu.hash               236       664
.dynsym                3576       904
.dynstr                1666      4480
.gnu.version            298      6146
.gnu.version_r          112      6448
.rela.dyn              4944      6560
.rela.plt              2664     11504
.init                    23     14168
.plt                   1792     14192
.plt.got                 24     15984
.text                 74969     16016
.fini                     9     90988
.rodata               19997     91008
.eh_frame_hdr          2180    111008
.eh_frame             11456    113192
.init_array               8   2224112
.fini_array               8   2224120
.data.rel.ro           2616   2224128
.dynamic                512   2226744
.got                    968   2227256
.data                   616   2228224
.bss                   4832   2228864
.gnu_debuglink           52         0
Total                133654

换句话说,“sysv”格式的哪些小部分(部分)进入哪些大部分(textdatabss 部分),“伯克利”格式?

我试图通过查看总和来猜测这里。

换句话说,我想知道:

相关:

  1. [我的问题]https://electronics.stackexchange.com/questions/363931/how-do-i-find-out-at-compile-time-how-much-of-an-stm32s-flash-memory-and-dynami

答案如下:

TLDR;

.interp + .note.ABI-tag + .note.gnu.build-id + .gnu.hash + .dynsym + .dynstr 
+ .gnu.version + .gnu.version_r + .rela.dyn + .rela.plt + .init + .plt 
+ .plt.got + .text + .fini + .rodata + .eh_frame_hdr + .eh_frame
= text

.init_array + .fini_array + .data.rel.ro + .dynamic + .got + .data
= data

.bss = bss

另请参阅末尾带有黄色、蓝色和红色框的图像,以进行快速视觉总结。

详情:

首先,让我们用 size -x --format=berkeley /bin/lssize -x /bin/ls 以十六进制打印 berkeley 大小信息(同样的事情,因为 berkeley 是默认格式):

$ size -x /bin/ls
   text    data     bss     dec     hex filename
0x1e48a  0x1278  0x12e0  133602   209e2 /bin/ls

这是十六进制的 sysv 大小输出,通过 size -x --format=sysv /bin/ls:

获得
$ size -x --format=sysv /bin/ls
/bin/ls  :
section                 size       addr
.interp                 0x1c      0x238
.note.ABI-tag           0x20      0x254
.note.gnu.build-id      0x24      0x274
.gnu.hash               0xec      0x298
.dynsym                0xdf8      0x388
.dynstr                0x682     0x1180
.gnu.version           0x12a     0x1802
.gnu.version_r          0x70     0x1930
.rela.dyn             0x1350     0x19a0
.rela.plt              0xa68     0x2cf0
.init                   0x17     0x3758
.plt                   0x700     0x3770
.plt.got                0x18     0x3e70
.text                0x124d9     0x3e90
.fini                    0x9    0x1636c
.rodata               0x4e1d    0x16380
.eh_frame_hdr          0x884    0x1b1a0
.eh_frame             0x2cc0    0x1ba28
.init_array              0x8   0x21eff0
.fini_array              0x8   0x21eff8
.data.rel.ro           0xa38   0x21f000
.dynamic               0x200   0x21fa38
.got                   0x3c8   0x21fc38
.data                  0x268   0x220000
.bss                  0x12e0   0x220280
.gnu_debuglink          0x34        0x0
Total                0x20a16

接下来,如果你 运行 objdump -h /bin/ls,你会得到以下内容,它显示 /bin/ls [=115] 中的所有 输出部分 =]目标文件,或可执行文件。这些输出部分与 size -x --format=sysv /bin/ls 命令的输出相匹配,但具有 more-detailed 信息,例如 VMA(虚拟内存地址)和 LMA(加载内存地址)等信息:

$ objdump -h /bin/ls

/bin/ls:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .interp       0000001c  0000000000000238  0000000000000238  00000238  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  0000000000000254  0000000000000254  00000254  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  0000000000000274  0000000000000274  00000274  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     000000ec  0000000000000298  0000000000000298  00000298  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000df8  0000000000000388  0000000000000388  00000388  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       00000682  0000000000001180  0000000000001180  00001180  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  0000012a  0000000000001802  0000000000001802  00001802  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000070  0000000000001930  0000000000001930  00001930  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rela.dyn     00001350  00000000000019a0  00000000000019a0  000019a0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rela.plt     00000a68  0000000000002cf0  0000000000002cf0  00002cf0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         00000017  0000000000003758  0000000000003758  00003758  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          00000700  0000000000003770  0000000000003770  00003770  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .plt.got      00000018  0000000000003e70  0000000000003e70  00003e70  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .text         000124d9  0000000000003e90  0000000000003e90  00003e90  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .fini         00000009  000000000001636c  000000000001636c  0001636c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 15 .rodata       00004e1d  0000000000016380  0000000000016380  00016380  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame_hdr 00000884  000000000001b1a0  000000000001b1a0  0001b1a0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .eh_frame     00002cc0  000000000001ba28  000000000001ba28  0001ba28  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 18 .init_array   00000008  000000000021eff0  000000000021eff0  0001eff0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 19 .fini_array   00000008  000000000021eff8  000000000021eff8  0001eff8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 20 .data.rel.ro  00000a38  000000000021f000  000000000021f000  0001f000  2**5
                  CONTENTS, ALLOC, LOAD, DATA
 21 .dynamic      00000200  000000000021fa38  000000000021fa38  0001fa38  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got          000003c8  000000000021fc38  000000000021fc38  0001fc38  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 23 .data         00000268  0000000000220000  0000000000220000  00020000  2**5
                  CONTENTS, ALLOC, LOAD, DATA
 24 .bss          000012e0  0000000000220280  0000000000220280  00020268  2**5
                  ALLOC
 25 .gnu_debuglink 00000034  0000000000000000  0000000000000000  00020268  2**2
                  CONTENTS, READONLY

A Google search for "vma and lma meaning" brings me to this site, which has a useful quote from the GNU ld linker manual. Searching for that quote leads me ,其中方便地提供了引用的来源。因此,让我们直接从其原始来源引用引文:

Every loadable or allocatable output section has two addresses. The first is the VMA, or virtual memory address. This is the address the section will have when the output file is run. The second is the LMA, or load memory address. This is the address at which the section will be loaded. In most cases the two addresses will be the same. An example of when they might be different is when a data section is loaded into ROM, and then copied into RAM when the program starts up (this technique is often used to initialize global variables in a ROM based system). In this case the ROM address would be the LMA, and the RAM address would be the VMA.

You can see the sections in an object file by using the objdump program with the ‘-h’ option.

(来源:GNU linker script ld manual

这意味着 objdump -h 显示的任何没有 VMA 的输出部分都不是程序的一部分。这消除了 .gnu_debuglink 部分。

接下来,我们可以看到 .bss 部分与 berkeley bss 部分具有完全相同的大小 (0x12e0),因此匹配:

.bss = bss

bss 包含 zero-initialized 全局和静态变量.

那么,data 输出部分呢,它包含所有 NON-zero-initialized(即:用一些 non-zero 值初始化)全局和静态变量?

还有 text 输出部分呢,它包含所有 程序代码和常量(只读)静态和全局变量

嗯,通过逻辑推导和分析,并使用我的 prior knowledge about which sections go into Flash vs RAM vs both on microcontrollers,我确定 所有在 objdump -h 输出部分中标记为 READONLY 的部分(其中包含一些DATA(非zero-initialized、const(read-only)静态和全局变量)和一些CODE(实际程序逻辑)(也read-only))被存储到text输出部分

所以:

.interp + .note.ABI-tag + .note.gnu.build-id + .gnu.hash + .dynsym + .dynstr 
+ .gnu.version + .gnu.version_r + .rela.dyn + .rela.plt + .init + .plt 
+ .plt.got + .text + .fini + .rodata + .eh_frame_hdr + .eh_frame
= text

您可以通过计算所有尺寸的总和来确认这一点。十六进制:

1c + 20 + 24 + ec + df8 + 682 + 12a + 70 + 1350 + a68 + 17 + 700 + 18 + 124d9 + 9 + 4e1d 
+ 884 + 2cc0 = 1e48a

...这是 berkeley 大小输出中显示的 text 部分的大小。

您可以在下图中看到它们用黄色框起来。

因此,标记为 DATA 而不是 READONLY 的其余部分是 data 部分:

.init_array + .fini_array + .data.rel.ro + .dynamic + .got + .data
= data

再次,十六进制大小总和证实了这一点:

8 + 8 + a38 + 200 + 3c8 + 268 = 1278

...这是 berkeley 大小输出中 data 部分的大小。

您可以在下图中看到它们用蓝色框起来。

在这张图片中,您可以看到用不同颜色框起来的所有 3 个 berkely 输出部分:

  1. berkeley-format text 输出部分(read-only、程序逻辑和 const 静态和全局变量)用黄色框起来。
  2. berkeley-formatdata输出部分(非zero-initialized[即:other-than-zero初始化的]静态和全局变量)用蓝色框起来。
  3. berkeley-format bss 输出部分(zero-initialized 静态和全局变量)用红色框起来。

在查看微控制器目标文件的情况下,例如 STM32 mcu:

  1. 闪存使用量 = text + data,并且
  2. 静态和全局变量的 RAM 内存使用量 = bss + data
    1. 这意味着剩余的 RAM 用于堆栈(局部变量)和堆(动态内存分配)= RAM_total - (bss + data)

主要参考资料:

  1. GNU 链接器 (ld) 手册,“3.1 基本链接器脚本概念”部分:https://sourceware.org/binutils/docs/ld/Basic-Script-Concepts.html#Basic-Script-Concepts
  2. [我自己的问题]https://electronics.stackexchange.com/questions/363931/how-do-i-find-out-at-compile-time-how-much-of-an-stm32s-flash-memory-and-dynami