Несогласие инструментов для анализа размера раздела.bss файла ELF

Анализируя раздел.bss программы на C++, скомпилированной в виде файла ELF для платформы ARM, я наткнулся на несколько способов определения размера. Четыре способа, которые я протестировал, также упоминаются в инструменте вопросов для анализа размера секций ELF и символа.

Однако результаты были совсем другие:

bss size according to nm:       35380
bss size according to readelf:  37632
bss size according to size:     37888
bss size according to objdump:  37594

В чем может быть причина этого?

Скрипт Python, используемый для генерации вывода

#!/usr/bin/env python
import re
import subprocess
import sys

fname = sys.argv[1]

# nm
output = subprocess.check_output(['arm-none-eabi-nm','-l','-S','-C',fname])
size = 0
for line in output.splitlines():
    m = re.search('[0-9a-f]* ([0-9a-f]*) ([a-zA-Z]) ([^/]*)\s*([^\s]*)',line)
    if m:
        stype = m.group(2).strip()
        if stype in ['B','b']:
            size += int(m.group(1),16)

print "bss size according to nm: \t%i" % size

# readelf
output = subprocess.check_output(['arm-none-eabi-readelf','-S',fname])
for line in output.splitlines():
    m = re.search('bss\s+[A-Z]+\s+[0-9a-f]+ [0-9a-f]+ ([0-9a-f]+)',line)
    if m:
        print "bss size according to readelf: \t%i" % int(m.group(1),16)
        break

# size
output = subprocess.check_output(['arm-none-eabi-size',fname])
for line in output.splitlines():
    m = re.search('[0-9]+\s+[0-9]+\s+([0-9]+)',line)
    if m:
        print "bss size according to size: \t%i" % int(m.group(1))
        break

# objdump
output = subprocess.check_output(['arm-none-eabi-objdump','-C','-t','-j','.bss',fname])
size = 0
for line in output.splitlines():
    m = re.search('bss\s+([0-9a-f]*)\s+',line)
    if m:
        size += int(m.group(1),16)

print "bss size according to objdump: \t%i" % size

Редактировать: Одна вещь, которую я обнаружил, это то, что nm классифицирует статические переменные внутри функций (правильно) как слабые (V), хотя они могут быть частью.bss. Однако не все разделы, классифицируемые как V, являются частью.bss, поэтому я не могу просто добавить все V разделы к размеру. Так неужели эта задача невозможна с помощью nm?

1 ответ

Решение

Вот пример файла ассемблера, который производит исполняемый файл, который показывает некоторые вещи, которые могут произойти:

    .section .bss
    .globl var1
    .size var1, 1
var1:
    .skip 1

    .align 16777216
    .globl var2
    .size var2, 1048576
    .globl var3
    .size var3, 1048576
    .globl var4
    .size var4, 1048576
var2:
var3:
var4:
    .skip 1048576

    .text

    .globl main
main:
    xor %eax, %eax
    ret

size -x дает этот вывод:

   text    data     bss     dec     hex filename
  0x5c9   0x220 0x2100000   34605033    21007e9 a.out

eu-readelf -S показывает по существу ту же информацию:

[25] .bss                 NOBITS       0000000001000000 01000000 02100000  0 WA     0   0 16777216

Тем не менее, размеры символов, как показано eu-readelf -s, совсем разные:

   32: 0000000001000001       1 OBJECT  LOCAL  DEFAULT       25 completed.6963
   48: 0000000003000000 1048576 NOTYPE  GLOBAL DEFAULT       25 var2
   49: 0000000003000000 1048576 NOTYPE  GLOBAL DEFAULT       25 var4
   59: 0000000002000000       1 NOTYPE  GLOBAL DEFAULT       25 var1
   61: 0000000003000000 1048576 NOTYPE  GLOBAL DEFAULT       25 var3

Сумма их размеров 0x300002, а не 0x2100000. Этому способствуют два фактора:

  • Существует разрыв около 16 МиБ после var1 который не используется. Необходимо осуществить выравнивание var2, в связи с порядком, в котором определены переменные. Часть пространства используется повторно completed.6963,
  • var2, var3, var4 являются псевдонимами: значения символов одинаковы, поэтому существует только один объект, поддерживающий переменную.

Кроме того, между концом .data раздел и .bss раздел, вызванный .bss Требование выравнивания. При обычном динамическом загрузчике это просто приведет к не отображенной области памяти:

  LOAD           0x000e08 0x0000000000200e08 0x0000000000200e08 0x000220 0x000220 RW  0x200000
  LOAD           0x1000000 0x0000000001000000 0x0000000001000000 0x000000 0x2100000 RW  0x200000

Так size предположительно правильно, когда не учитывается этот пробел.

Числа в этом примере, конечно, чрезмерны, но эти эффекты видны даже с обычными двоичными файлами, только в меньшей степени.

readelf/size а также objdump/nm различия могут быть особенностью ARM; они, вероятно, вызваны определенными типами символов, которых нет в моем примере.

Другие вопросы по тегам