• 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	   data	    bss	    oct	    hex	filename" :
    	  "   text	   data	    bss	    dec	    hex	filename");
    
      /* 打印具体的数值 */
      rprint_number (7, textsize);
      putchar ('	');
      rprint_number (7, datasize);
      putchar ('	');
      rprint_number (7, bsssize);
      printf (((radix == octal) ? "	%7lo	%7lx	" : "	%7lu	%7lx	"),
    	  (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 ("
    ");
    }
    
    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格式

  • 相关阅读:
    PE格式详细讲解10 系统篇10|解密系列
    复杂的数据类型1 C++快速入门07
    复杂的数据类型2 C++快速入门08
    复杂的数据类型2 C++快速入门08
    复杂的数据类型1 C++快速入门07
    PE格式详细讲解10 系统篇10|解密系列
    Win32基础知识1 Win32汇编语言002
    开题篇 Win32汇编语言001
    开题篇 Win32汇编语言001
    Win32基础知识1 Win32汇编语言002
  • 原文地址:https://www.cnblogs.com/gmpy/p/11376374.html
Copyright © 2020-2023  润新知