Введение
Я пытаюсь сделать статическую оценку максимально возможного использования стека во встроенной программе.
Мне удалось получить использование стека каждой отдельной функции с помощью опции GCC -fstack-usage
, и я построил дерево всех вызовов функций, анализируя RTL, полученный с помощью опции -fdump-rtl-expand
.
Теперь остается только самая легкая часть, когда я устанавливаю использование стека для каждой функции в своем дереве и ищу самый дорогой путь, используя какой-то алгоритм Дейкстры.
Однако выяснилось, что выяснение того, какая функция из файла использования стека коррелирует с тем, какая функция из файла RTL, по-видимому, является самой сложной частью всей работы.
Проблема
Так в чем именно проблема?
Короче говоря, идентификаторы функций, сгенерированные GCC для двух файлов, различны.
RTL использует как искаженные идентификаторы, так и понятные человеку имена. Последние похожи на те, которые вы можете увидеть в исходном коде.
Файл использования стека имеет только удобочитаемые имена, но они записаны в какой-то странной записи, которая полностью отличается от записи в файле RTL.
Давайте рассмотрим пример.
Исходный файл test.cpp
:
void test() {}
Команда (набор инструментов: GCC v8.2.0):
g++ -c test.cpp -fdump-rtl-expand -fstack-usage
RTL-файл ./test.cpp.234r.expand
:
;; Function test (_Z4testv, funcdef_no=0, decl_uid=2358, cgraph_uid=0, symbol_order=0)
;; Generating RTL for gimple basic block 2
try_optimize_cfg iteration 1
Merging block 3 into block 2...
Merged blocks 2 and 3.
Merged 2 and 3 without moving.
Merging block 4 into block 2...
Merged blocks 2 and 4.
Merged 2 and 4 without moving.
try_optimize_cfg iteration 2
;;
;; Full RTL generated for this function:
;;
(note 1 0 3 NOTE_INSN_DELETED)
(note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
(note 2 3 7 2 NOTE_INSN_FUNCTION_BEG)
(insn 7 2 0 2 (const_int 0 [0]) "test.cpp":1 -1
(nil))
Файл использования стека test.su
:
test.cpp:1:6:void test() 16 static
Таким образом, функция называется test
и _Z4testv
в файле RTL и void test()
в файле использования стека.
Еще сложнее сказать, какие функции одинаковы, когда мы получаем реальный пример из моего кода.
Имена будут тогда (по порядку):
devices::Button<virtualIo::Port_<utils::type::list::List<virtualIo::IndexedPin_<0, virtualIo::PortD, 7, true> >, 1, unsigned char, utils::type::list::List<virtualIo::PortShifter_<virtualIo::PortD, unsigned char, unsigned char, false, 128, 1, utils::type::list::List<virtualIo::PartShifter_<unsigned char, unsigned char, 1, 7, 128> > > >, true>, true>::isUp
_ZNK7devices6ButtonIN9virtualIo5Port_IN5utils4type4list4ListIJNS1_11IndexedPin_ILh0ENS1_5PortDELh7ELb1EEEEEELh1EhNS6_IJNS1_12PortShifter_IS8_hhLb0ELh128ELh1ENS6_IJNS1_12PartShifter_IhhLh1ELa7ELh128EEEEEEEEEEELb1EEELb1ELb0EE4isUpEv
bool devices::Button<PORT, POSITIVE_INPUT, PULL_UP>::isUp() const [with PORT = virtualIo::Port_<utils::type::list::List<virtualIo::IndexedPin_<0, virtualIo::PortD, 7, true> >, 1, unsigned char, utils::type::list::List<virtualIo::PortShifter_<virtualIo::PortD, unsigned char, unsigned char, false, 128, 1, utils::type::list::List<virtualIo::PartShifter_<unsigned char, unsigned char, 1, 7, 128> > > >, true>; bool POSITIVE_INPUT = true; bool PULL_UP = false]
Решение о том, что это та же функция, едва ли выполнимо человеком, и я понятия не имею, как это сделать с помощью скрипта / программы.
Предложения по решению
Идеальным решением было бы иметь искаженные имена в файле использования стека. Они единообразны и недвусмысленны (за исключением незначительных неудобств с конструкторами и деструкторами).
Я приму любой способ, позволяющий надежно сопоставлять имена из одного файла с другим.
В крайнем случае я буду вынужден сопоставлять функции по их порядку, который в обоих файлах одинаков. Однако я очень не решаюсь делать это предположение.
GCC версия
Убедитесь, что для этого используется версия 8 GCC. Похоже, что версия 7 генерирует имена по-другому.
Я тестировал версии 8.2.0 и 8.3.0. Оба имеют описанное поведение.
Я не могу использовать версию 7. В ней есть какая-то ошибка, препятствующая компиляции моего кода.
Редактировать
Дополнительные примеры
Исходный файл test.cpp
:
template<typename T> long some_name(int); template<> long some_name<int>(int) { return 0; }
Первая строка файла RTL ./test.cpp.234r.expand
:
;; Function some_name<int> (_Z9some_nameIiEli, funcdef_no=0, decl_uid=2364, cgraph_uid=0, symbol_order=0)
Файл использования стека test.su
:
test.cpp:5:6:long int some_name(int) [with T = int] 16 static
Edit2
Эксперименты показали, что читаемые человеком идентификаторы из файлов RTL не являются уникальными.
Они одинаковы для перегруженных функций.