代码之家  ›  专栏  ›  技术社区  ›  B.Gen.Jack.O.Neill

关于C编译器asm输出的另一个问题

  •  2
  • B.Gen.Jack.O.Neill  · 技术社区  · 14 年前

    给你一个很快的问题。当我在C中存储一些自动变量时,asm输出如下: MOV ESP+4,#25h ,我只想知道为什么编译器不能计算它 ESP+4

    我想得很透彻,但我真的找不到理由。我是说,编译器不知道esp的值吗?应该是的。当使用另一个对象文件时,这应该也不是问题,因为变量可以用地址表示,然后在所有自动变量都已知的情况下进行链接,因此可以分配适当的地址。谢谢。

    5 回复  |  直到 14 年前
        1
  •  3
  •   stakx - no longer contributing Saravana Kumar    14 年前

    不,它不能知道 esp 提前。

    以一个递归函数为例,即一个调用自身的函数。假设这样一个函数有几个通过堆栈传入的参数。这意味着每个参数占用堆栈上的一些空间,从而更改 注册。

    现在,当函数被输入时 将取决于函数以前调用自身的次数,编译器在编译时不可能知道这一点。如果您对此表示怀疑,请使用如下函数:

    void foobar(int n)
    {
        if (rand() % n != 17)
            foobar(n + 1);
    }
    

    如果编译器想确定 静电除尘器 事先,它必须为函数的每个可能值创建一个版本 静电除尘器 .

    静电除尘器 --这显然不合情理。


    附笔。: 现在是另一回事。你其实不需要优化 [esp+N] [esp] ... 至少不是在英特尔奔腾CPU上。您可以说,它们已经包含了针对这个甚至更复杂场景的优化。如果您对英特尔CPU感兴趣,我建议您查阅文档中的 模式R/M 以及 同胞 机器指令的字节,例如。 here for the SIB byte here 当然,也可以在英特尔的官方CPU开发者文档中找到。

        2
  •  3
  •   Carl Norum    14 年前

    不,编译器不知道 ESP 在运行时-它是堆栈指针。每次调用函数时,它都可能不同。也许最简单的例子就是递归函数——每次它调用自己时,堆栈都会更深一点,以容纳新调用的局部变量。每个堆栈帧都有自己的局部变量,每个堆栈帧位于堆栈上的不同位置,因此有自己的地址(in 静电除尘器 ,正常情况下)。

        3
  •  2
  •   FRotthowe    14 年前

        4
  •  2
  •   Jerry Coffin    14 年前

    不,编译器没有提前知道值。在一些非常基本的程序中(只有一条可能的“路线”从 main 任何其他被调用的特定函数)它 能够 ,但我不知道有哪个编译器会尝试计算这个。如果有任何递归,或者函数是从多个位置调用的,则堆栈指针的值将不同,具体取决于调用它的位置。

    在任何情况下这样做都没有什么意义——因为堆栈指针 由于大量使用,大多数CPU的设计都使得从堆栈指针进行间接寻址非常有效。事实上,它通常比提供一个绝对地址更有效。

        5
  •  1
  •   Hans Passant    14 年前

    这对于堆栈的工作方式来说是非常基本的。为了自己解释清楚,想象一下如何实现递归函数。