Stack frame omission (FPO) optimization and consequences when debugging, part 1

During the course of debugging programs, you’ve probably ran into the term “FPO” once or twice. FPO refers to a specific class of compiler optimizations that, on x86, deal with how the compiler accesses local variables and stack-based arguments.

With a function that uses local variables (and/or stack-based arguments), the compiler needs a mechanism to reference these values on the stack. Typically, this is done in one of two ways:

  • Access local variables directly from the stack pointer (esp). This is the behavior if FPO optimization is enabled. While this does not require a separate register to track the location of locals and arguments, as is needed if FPO optimization is disabled, it makes the generated code slightly more complicated. In particular, the displacement from esp of locals and arguments actually changes as the function is executed, due to things like function calls or other instructions that modify the stack. As a result, the compiler must keep track of the actual displacement from the current esp value at each location in a function where a stack-based value is referenced. This is typically not a big deal for a compiler to do, but in hand written assembler, this can get a bit tricky.
  • Dedicate a register to point to a fixed location on the stack relative to local variables and and stack-based arguments, and use this register to access locals and arguments. This is the behavior if FPO optimization is disabled. The convention is to use the ebp register to access locals and stack arguments. Ebp is typically setup such that the first stack argument can be found at [ebp+08], with local variables typically at a negative displacement from ebp.

A typical prologue for a function with FPO optimization disabled might look like this:

push   ebp               ; save away old ebp (nonvolatile)
mov    ebp, esp          ; load ebp with the stack pointer
sub    esp, sizeoflocals ; reserve space for locals
...                      ; rest of function

The main concept is that FPO optimization is disabled, a function will immediately save away ebp (as the first operation touching the stack), and then load ebp with the current stack pointer. This sets up a stack layout like so (relative to ebp):

[ebp-01]   Last byte of the last local variable
[ebp+00]   Old ebp value
[ebp+04]   Return address
[ebp+08]   First argument...

Thereafter, the function will always use ebp to access locals and stack based arguments. (The prologue of the function may vary a bit, especially with functions using a variation __SEH_prolog to setup an initial SEH frame, but the end result is always the same with respect to the stack layout relative to ebp.)

This does (as previously stated) make it so that the ebp register is not available for other uses to the register allocator. However, this performance hit is usually not enough to be a large concern relative to a function compiled with FPO optimization turned on. Furthermore, there are a number of conditions that require a function to use a frame pointer which you may hit anyway:

  • Any function using SEH must use a frame pointer, as when an exception occurs, there is no way to know the displacement of local variables from the esp value (stack pointer) at exception dispatching (the exception could have happened anywhere, and operations like making function calls or setting up stack arguments for a function call modify the value of esp).
  • Any function using automatic C++ objects with destructors must use SEH for compiler unwind support. This means that most C++ functions end up with FPO optimization disabled. (It is possible to change the compiler assumptions about SEH exceptions and C++ unwinding, but the default [and recommended setting] is to unwind objects when an SEH exception occurs.)
  • Any function using _alloca to dynamically allocate memory on the stack must use a frame pointer (and thus have FPO optimization disabled), as the displacement from esp for local variables and arguments can change at runtime and is not known to the compiler at compile time when code is being generated.

Because of these restrictions, many functions you may be writing will already have FPO optimization disabled, without you having explicitly turned it off. However, it is still likely that many of your functions that do not meet the above criteria have FPO optimization enabled, and thus do not use ebp to reference locals and stack arguments.

Now that you have a general idea of just what FPO optimization does, I’ll cover cover why it is to your advantage to turn off FPO optimization globally when debugging certain classes of problems in the second half of this series. (It is actually the case that most shipping Microsoft system code turns off FPO as well, so you can rest assured that a real cost benefit analysis has been done between FPO and non-FPO optimized code, and it is overall better to disable FPO optimization in the general case.)

Update: Pavel Lebedinsky points out that the C++ support for SEH exceptions is disabled by default for new projects in VS2005 (and that it is no longer the recommended setting). For most programs built prior to VS2005 and using the defaults at that time, though, the above statement about C++ destructors causing SEH to be used for a function (and thus requiring the use of a frame pointer) still applies.

Stack frame omission (FPO) optimization part1相关推荐

  1. C的function call與stack frame心得

    为什么80%的码农都做不了架构师?>>>    [技術] C的function call與stack frame心得 Written on 12:00 上午 by Yu Lai 從大 ...

  2. LWN:Fedora关于stack frame的争论!

    关注了就能看到更多这么棒的文章哦- Fedora's tempest in a stack frame By Jonathan Corbet January 16, 2023 DeepL assist ...

  3. 浅谈函数栈帧(Stack Frame)

  4. 框架指针省略(Frame Pointer Omission)(FPO)

    框架指针省略(Frame Pointer Omission)(FPO) FPO是一种优化,它压缩或者省略了在栈上为该函数创建框架指针的过程.这个选项加速了函数调用,因为不需要建立和移除框架指针(ESP ...

  5. 关闭编译器FPO优化

    // The release libs don't include FPO debug information, so FPO // optimization will interfere with ...

  6. 框架指针的省略(FPO)

    框架指针省略(Frame Pointer Omission)(FPO) FPO是一种优化,它压缩或者省略了在栈上为该函数创建框架指针的过程.这个选项加速了函数调用,因为不需要建立和移除框架指针(ESP ...

  7. 汇编语言基础之七- 框架指针的省略(FPO)

     框架指针省略(Frame Pointer Omission)(FPO) FPO是一种优化,它压缩或者省略了在栈上为该函数创建框架指针的过程.这个选项加速了函数调用,因为不需要建立和移除框架指针( ...

  8. 从零学习Java之旅 Part1 基本概念部分

    从零开始学Java之旅 Part1 基本概念部分 从零学习Java之旅 Part1 基本概念部分 Java学前了解知识 本人说明 Java语言版本 Java语言平台版本 Java语言特点 JDK和JR ...

  9. Chapter 5. The Stack

    Chapter 5. The Stack Introduction A Real-World Analogy Stacks in x86 and x86-64 Architectures What I ...

最新文章

  1. mysql登陆提示ERROR 1045 (28000): Access denied for user
  2. 不使用 Maven 等构建工具,而使用原始方法在 IntelliJ IDEA 中整合 Tomcat 部署 Web 应用
  3. [Java in NetBeans] Lesson 06. Custom classes
  4. python官网网址是什么意思_大家都是怎么部署python网站的?
  5. git 上传项目到linux仓库_使用子模块和子树来管理 Git 项目 | Linux 中国
  6. magento模板制作教程(一)
  7. centos7部署posgresql和kong总结
  8. 经典——也许这就是方向
  9. 一个普通的 Zepto 源码分析(一) - ie 与 form 模块
  10. re正则表达式7_{}
  11. TI单芯片毫米波雷达代码走读(十八)—— 多普勒维CA-CFAR检测之C代码实现
  12. 读胡适先生《赠与今年的大学毕业生》和《赠与大学毕业生的话》后感
  13. 激荡三十年——互联网的崛起
  14. 【电力电子】【2013】基于对称分量提取的三电平三相并网变流器电压暂降时的电网同步与控制
  15. 草木有本心,何求美人折
  16. 2022煤矿井下爆破考试题库模拟考试平台操作
  17. 有多少人工智能在“人工”强行“智能”
  18. 移动端蚂蚁组件(antd-mobile)- 解决日期组件中的语系问题
  19. 微信技术交流群两个月来的情况
  20. docx批量转换成html,Batch DOCX to HTML Converter(批量docx转换HTML工具)

热门文章

  1. 解读:小比尔 · 福特认为特斯拉的成功并非因为马斯克
  2. java 查找大写字母_在Java中查找字符串的所有大写字母
  3. 加盟代理小程序为创业者带来另一条出路
  4. 大数据面试之hive重点(二)
  5. 谷歌浏览器chrome 自己写的插件使用教程
  6. android下开启AP热点
  7. HDU1507 Uncle Tom's Inherited Land*
  8. iOS 11 发布!巨大进步、里程碑式飞跃!
  9. 未来的无盘网吧是什么样子?
  10. shell脚本小游戏