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支持兩種輸出格式sysv
和berkeley
,對同一個文件,看看執行效果有什麼差異
[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_format
和print_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_sum
和sysv_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
格式