简体   繁体   English

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

[英]Another question about C compiler asm output

very quick question for you. 很快你的问题。 When I store some automatic variable in C, asm output is like this: MOV ESP+4,#25h , and I just want to know why can´t compiler calculate that ESP+4 adress itself. 当我在C中存储一些自动变量时,asm输出是这样的: MOV ESP+4,#25h ,我只是想知道为什么编译器无法计算ESP+4地址。

I thought this through, and I really cant find reason for this. 我想通了,我真的找不到理由。 I mean, isnt compiler aware of the esp value? 我的意思是,不是编译器知道esp值吗? It should be. 它应该是。 And when using another object file, this should not be problem either, since variables could just be represent by adress and linked later, when all automatic variables are known, and therefore proper adress could be assigned. 当使用另一个目标文件时,这也不应该是问题,因为变量可以只是由地址表示并在以后链接,当所有自动变量都已知时,因此可以分配正确的地址。 Thanks. 谢谢。

No, the compiler is not aware of the value of ESP at runtime - it's the stack pointer. 不,编译器在运行时不知道ESP的值 - 它是堆栈指针。 It is potentially different every time the function is called. 每次调用函数时它都可能不同。 Perhaps the simplest example to think about is a recursive function - every time it calls itself, the stack gets a little bit deeper to accommodate the local variables for the new call. 也许最简单的例子是递归函数 - 每次调用自身时,堆栈会更深入地适应新调用的局部变量。 Every stack frame has its own local variable, every stack frame is at a different position on the stack, and therefore has its own address (in ESP , normally). 每个堆栈帧都有自己的局部变量,每个堆栈帧都位于堆栈的不同位置,因此有自己的地址(通常在ESP )。

No, it cannot know the value of esp in advance. 不,它无法提前知道esp的价值。

Take for example a recursive function, ie. 以递归函数为例,即。 a function that calls itself. 一个自称的函数。 Assume such a function has several parameters that are passed in via the stack. 假设这样的函数有几个通过堆栈传入的参数。 This means that each argument takes some space on the stack, thereby changing the value of the esp register. 这意味着每个参数在堆栈上占用一些空间,从而改变esp寄存器的值。

Now, when the function is entered, the exact value of esp will depend on how many times the function has called itself previously, and there is no way the compiler could know this at compile time. 现在,当输入函数时, esp的确切值将取决于函数先前调用自身的次数,编译器无法在编译时知道这一点。 If you doubt this, take a function such as this: 如果你怀疑这一点,请采取如下函数:

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

There's no way the compiler would be smart enough in advance to figure out if the function will call itself once more. 编译器无法提前足够聪明地判断该函数是否会再次调用自身。

If the compiler wanted to determine esp in advance, it would effectively have to create a version of the function for each possible value for esp . 如果编译器想要提前确定esp ,则实际上必须为esp每个可能值创建函数的版本。

The above explanation only takes into account one function. 以上说明仅考虑一个功能。 In a real-world scenario, a program has many functions which interdepend on one another, which results in fairly complex "call graphs". 在现实世界的场景中,程序具有许多彼此相互依赖的功能,这导致相当复杂的“调用图”。 This together with (among other things) unpredicable program logic means the compiler would have to create a huge array of versions of each function, just to optimise on esp -- which clearly doesn't make sense. 这与(以及其他)不可预测的程序逻辑一起意味着编译器必须创建每个函数的大量版本,只是为了优化esp - 这显然没有意义。


PS: Now something else. PS:现在别的了。 You don't actually need to optimise [esp+N] at all, because it should not take any more CPU time than the simpler [esp] ... at least not on Intel Pentium CPUs. 实际上你根本不需要优化[esp+N] ,因为它不应该比简单的[esp]花费更多的CPU时间......至少在Intel Pentium CPU上没有。 You could say that they already contain optimizations for exactly this and even more complicated scenarios. 你可以说它们已经包含了针对这个甚至更复杂场景的优化。 If you're interested in the Intel CPUs, I suggest you look up the documentation for something called the MOD R/M and the SIB byte of a machine instruction, eg here for the SIB byte or here or, of course, in Intel's official CPU developer documentation. 如果你有兴趣在Intel的CPU,我建议你查查称为MOD R / M和机器指令的SIB字节的东西的文档,例如这里的SIB字节这里或,当然,在英特尔的官方CPU开发人员文档。

The Stack Pointer cannot be calculated at compile time. 堆栈指针无法在编译时计算。 For a simple example why this is not possible, just think of a recursive function: The same variable has a different address for each call, but it's always the same code that is run. 举一个简单的例子,为什么这是不可能的,只需考虑一个递归函数:同一个变量为每个调用都有不同的地址,但它始终与运行的代码相同。

No, the compiler doesn't know the value ahead of time. 不,编译器不会提前知道值。 In a few extremely basic programs (where there's only one possible "route" from main to any other particular function being called) it could , but I don't know of a compiler that attempts to compute this. 在一些非常基本的程序中(从main到任何其他特定函数只有一个可能的“路由”被调用)它可以 ,但我不知道编译器试图计算这个。 If you have any recursion, or a function is called from more than one place, the the stack pointer will have different values depending on where it was called from. 如果您有任何递归,或者从多个位置调用函数,则堆栈指针将具有不同的值,具体取决于它的调用位置。

There's not much point to doing so in any case -- since the stack pointer is so heavily used, most CPUs are designed to make indirect addressing from the stack pointer extremely efficient. 没有太多的点在任何情况下这样做-由于堆栈指针如此频繁使用,大部分的CPU的设计使间接从栈指针非常有效的解决。 In fact, it's often more efficient than supplying an absolute address would be. 实际上,它通常比提供绝对地址更有效。

This is really rather fundamental to the way the stack works. 这对堆栈的工作方式来说非常重要。 To reason it out for yourself, imagine how you'd implement a recursive function. 为了自己解释一下,想象一下如何实现递归函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM