size命令的sysv和berkeley格式差別

size命令使用說明

size命令用於顯示二進制文件的段(節)大小,其功能類似於readelf -S,詳細的說明如下:

用法:size [選項] [文件]
 顯示二進制文件中節的大小
 沒有給出輸入文件,默認爲 a.out
 The options are:
  -A|-B     --format={sysv|berkeley}  Select output style (default is berkeley)
  -o|-d|-x  --radix={8|10|16}         Display numbers in octal, decimal or hex
  -t        --totals                  Display the total sizes (Berkeley only)
            --common                  Display total size for *COM* syms
            --target=<bfdname>        Set the binary file format
            @<file>                   Read options from <file>
  -h        --help                    Display this information
  -v        --version                 Display the program's version

size:支持的目標: elf64-x86-64 elf32-i386 elf32-x86-64 a.out-i386-linux pei-i386  
pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big  
pe-x86-64 pe-i386 plugin srec symbolsrec verilog tekhex binary ihex

背景

size支持兩種輸出格式sysvberkeley,對同一個文件,看看執行效果有什麼差異

[GMPY@11:41 tmp]$size test
   text    data     bss     dec     hex filename
   1810     584       8    2402     962 test
[GMPY@11:41 tmp]$size --format=sysv test
test  :
section              size      addr
...
.text                 640   4195616
...
.data                  16   6295624
.bss                    8   6295640
...
Total                2496

爲了方便了解,這裏補充以下3個重要段的功能:

段名 功能
BSS 存放程序中未初始化的全局變量的一塊內存區域
DATA 存放程序中已初始化的全局變量的一塊內存區域
TEXT/CODE 存放程序執行代碼的一塊內存區域

可以發現,test/data/bss段的大小不一致呀,我該相信哪一個?

源碼

size命令是binutils軟件包提供的子命令,在GNU的官網中找到其最新源碼(2.32)

廢話不多說,下載,解壓,直接看源碼(binutils/size.c)

static void
print_sizes (bfd *file)
{
  if (show_common)
    calculate_common_size (file);
  if (berkeley_format)
    print_berkeley_format (file);
  else
    print_sysv_format (file);
}

根據不同格式選擇不同的打印方式,妥了,直接對比print_berkeley_formatprint_sysv_format

對比print_berkeley_format與print_sysv_format

berkeley格式

static void
print_berkeley_format (bfd *abfd)
{
  ...
  bsssize = 0;
  datasize = 0;
  textsize = 0;

  /*
   * 獲取bss/data/text段大小
   * 找不到bfd_map_over_sections的定義,但猜測是一個宏
   * 功能:對每一個段調用berkeley_sum函數進行處理
   */
  bfd_map_over_sections (abfd, berkeley_sum, NULL);

  /* 打印信息頭 */
  if (files_seen++ == 0)
    puts ((radix == octal) ? "   text\t   data\t    bss\t    oct\t    hex\tfilename" :
      "   text\t   data\t    bss\t    dec\t    hex\tfilename");

  /* 打印具體的數值 */
  rprint_number (7, textsize);
  putchar ('\t');
  rprint_number (7, datasize);
  putchar ('\t');
  rprint_number (7, bsssize);
  printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"),
      (unsigned long) total, (unsigned long) total);
  ...
}

sysv格式

static void
print_sysv_format (bfd *file)
{
  svi_total = 0;
  svi_maxvma = 0;
  svi_namelen = 0;

  /*
   * 獲取bss/data/text段大小
   * 找不到bfd_map_over_sections的定義,但猜測是一個宏
   * 功能:對每一個段調用sysv_internal_printer函數進行處理
   */
  bfd_map_over_sections (file, sysv_internal_printer, NULL);
  if (show_common)
    {
      svi_total += common_size;
      sysv_one_line ("*COM*", common_size, 0);
    }
  ......
}

好吧,我們關注的是兩者的數值差異,需要進一步對比子函數berkeley_sumsysv_internal_printer

對比berkeley_sum和sysv_internal_printer

berkeley格式

static void
berkeley_sum (bfd *abfd ATTRIBUTE_UNUSED, sec_ptr sec,
          void *ignore ATTRIBUTE_UNUSED)
{
  flagword flags;
  bfd_size_type size;

  flags = bfd_get_section_flags (abfd, sec);
  if ((flags & SEC_ALLOC) == 0)
    return;

  size = bfd_get_section_size (sec);

  /* 根據不同段的屬性,進行不同類別的累加 */
  if ((flags & SEC_CODE) != 0 || (flags & SEC_READONLY) != 0)
    /* text/code 段 */
    textsize += size;
  else if ((flags & SEC_HAS_CONTENTS) != 0)
    /* data 段 */
    datasize += size;
  else
    /* bss 段 */
    bsssize += size;
}

sysv格式:

static void
sysv_one_line (const char *name, bfd_size_type size, bfd_vma vma)
{
  printf ("%-*s   ", svi_namelen, name);
  rprint_number (svi_sizelen, size);
  printf ("   ");
  rprint_number (svi_vmalen, vma);
  printf ("\n");
}

static void
sysv_internal_printer (bfd *file ATTRIBUTE_UNUSED, sec_ptr sec,
               void *ignore ATTRIBUTE_UNUSED)
{
  bfd_size_type size = bfd_section_size (file, sec);

  if (   ! bfd_is_abs_section (sec)
      && ! bfd_is_com_section (sec)
      && ! bfd_is_und_section (sec))
    {
      svi_total += size;

      /* 分別打印出每一個段的信息 */
      sysv_one_line (bfd_section_name (file, sec),
             size,
             bfd_section_vma (file, sec));
    }
}

結論

實錘了,berkeley格式與sysv格式下的bss/data/text是不同的含義,其中

  • sysv是實打實的打印出每一個段的大小,等效於readelf -S
  • berkeley是統計的結果,把代碼段和只讀的段統計到text段,把有內容的段統計到data段,其他全歸屬bss段

在只需要知道分類的統計結果時用berkelay格式,在需要明細到每一個段時採用sysv格式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章