0

介绍

我正在尝试对嵌入式程序中最大可能的堆栈使用进行静态评估。我已经设法通过使用 GCC 选项来获取每个单独函数的堆栈使用情况,-fstack-usage并且我已经通过解析 option 生成的 RTL 构建了所有函数调用的树-fdump-rtl-expand

现在,当我为树中的每个函数设置堆栈使用并使用某种 Dijkstra 算法寻找最昂贵的路径时,只剩下简单的部分了。然而,事实证明,从堆栈使用文件中找出哪个函数与 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

因此该函数在 RTL 文件和test堆栈使用文件中被命名。_Z4testvvoid 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。看起来版本 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

编辑2

实验表明,来自 RTL 文件的人类可读标识符不是唯一的。对于重载函数,它们是相同的。

4

0 回答 0