【问题标题】:Why is dynamic link required in function activation record? (in static scoped language)为什么功能激活记录需要动态链接? (在静态范围语言中)
【发布时间】:2016-06-03 16:11:05
【问题描述】:

我读到动态链接指向上一个激活记录,因此它在动态范围编程语言中是有意义的。但是在静态范围的编程语言中,为什么访问链接(指向较低嵌套级别中函数的激活记录)还不够呢? 特别是在 C 中 - 为什么不需要访问链接?为什么需要动态链接?

【问题讨论】:

  • 提供更多上下文。我从未听说过与编程语言 C 一起使用的术语“激活记录”。
  • 也许 OP 在谈论 THIS
  • 这是否与共享库中的静态变量有关?

标签: c programming-languages


【解决方案1】:

我将使用这个我更熟悉的命名法:

激活记录:堆栈帧

动态链接:[保存]帧指针

所以,我将您的问题解释为:为什么需要帧指针?[1]

帧指针不需要

某些编译器(例如 Green Hills C++、带 -O2 的 GCC)通常不会生成或可能会被要求不生成(MSVC、GCC)。

也就是说,它当然有它的好处:

  • 轻松遍历call stack:生成stack trace 就像遍历帧指针构成头部的链表一样简单。使实现堆栈跟踪和调试器变得更加容易。

  • 更轻松的代码生成:堆栈变量可以通过索引帧指针而不是随时变化的堆栈指针来引用。堆栈指针随每次 push/pop 变化,帧指针在函数内保持不变(prologue/epilogue 之间)

  • 如果出现问题,stack unwinding 可以使用帧指针来完成。这就是 Borland 的结构化异常处理 (SEH) 的工作原理。

  • 简化堆栈管理:特别是 setjmp(3)alloca(3)C99-VLA 的实现可能(并且通常会)依赖它。

缺点:

  • 寄存器用法:x86 只有 8 个通用寄存器。其中之一需要完全专用于保存帧指针。
  • 开销:为每个功能生成序言/尾声。

但正如您所注意到的,编译器可以生成完美的代码,而无需维护帧指针。


[1] 如果不是这个意思,请详细说明。

【讨论】:

  • 也许动态链接是“显示链接”而不是“帧指针”
  • @BasileStarynkevitch 我理解的方式是,动态链接将函数的激活记录与其动态前任(即调用者的激活框架)链接起来。因此我将这个问题解释为:为什么我们需要帧指针。但我不完全确定这是否是 OP 的想法。我编辑了我的答案以反映这一点。
【解决方案2】:

您的问题可能与GCC-fomit-frame-pointer optimizing option 有关,请参阅this

顺便说一句,很多人将调用框架(在call stack)中命名为激活记录continuation 的概念以及 continuation passing styleA-normal forms 的概念密切相关。

动态链接实际上只对nested 函数有用(可能还有closures),而标准C 没有它们。有些人谈到显示链接。标准 C 没有嵌套函数,因此不需要任何相关技巧(显示链接、蹦床等)。

GCC 编译器提供nested functions 作为C 语言扩展,并通过激活记录上的动态链接实现它们,与您的想法非常接近。另请阅读 man or boy testtrampoline 上的维基页面。

【讨论】:

    猜你喜欢
    • 2021-10-22
    • 1970-01-01
    • 2020-08-02
    • 2014-12-12
    • 2011-03-05
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    相关资源
    最近更新 更多