C++编译器如何编译变量名?

10

我明白我表达不够清晰。我的疑惑,我认为,可以总结为:

在一个可执行文件(机器码)中,“变量”是如何表示的?它们是静态内存地址吗?编译器会给每个变量分配一个特定的“名称”(还是只保留您给它们的名称)?

用代码来表达:

 int x=5;
 //Bunch of code
 cin>>y;
 cout<<x+1;

每台计算机中的程序如何知道哪个地址将持有值5,以保存输入的值、将1添加到它现在持有的值并最终打印相同的值。

-- João

3个回答

8

这是与实现相关的。

通常,变量的位置将基于各种因素和优化。它们可能根本不会存在于RAM中,因为它们可能被优化以完全存在于寄存器中,或者被完全优化掉。

变量名在运行时不存在;它们在编译期间被丢弃。但是,编译器可以发出存储在应用程序二进制文件中的调试信息,以允许开发人员调试应用程序。尽管如此,这通常会在发布版本中删除。

我对Gameshark的具体情况一无所知。但在许多情况下,通过查看应用程序的机器代码可以找到特定变量的位置。


@JoãoSilva:你最初的问题并没有太多意义,编译器不会“编译变量名”。我的回答是试图解释我认为你想知道的内容。 - Oliver Charlesworth
@DavidHeffernan 不是总是这样的,链接器可能需要它们。 - Seth Carnegie
1
@JoãoSilva:关于“变量是否总是被赋予相同的地址?”这个问题。情况比较复杂。在旧平台上,如果我们俩运行完全相同的应用程序,则特定变量将驻留在(虚拟)内存中的相同位置。在现代系统上,诸如[ASLR](http://en.wikipedia.org/wiki/ASLR)之类的功能会影响这些事情。 - Oliver Charlesworth
该死!那真的很难!那正是我在寻找的答案类型。谢谢你! - João Silva
1
那么你的问题是,编译器是如何工作的? - David Heffernan
显示剩余8条评论

7

这是一个简单的C语言程序:

int main() {
    int a = 5;
    int b = 7;

    int c = a + b;

    return 0;
}

如果您在Linux下使用gcc -m32 -S -O0 -o main.s main.c 进行编译,您将得到类似于以下内容的结果。
    .file   "main.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    /* %ebp is a Base Pointer Register */
    pushl   %ebp
    movl    %esp, %ebp

    /* Here we reserve space for our variables */
    subl    $16, %esp

    /* a's address is %ebp - 4 */
    movl    $5, -4(%ebp)

    /* b's address is %ebp - 8 */
    movl    $7, -8(%ebp)

    /* a + b */
    movl    -8(%ebp), %eax
    movl    -4(%ebp), %edx
    addl    %edx, %eax

    /* c's address is %ebp - 12 */
    movl    %eax, -12(%ebp)

    /* return 0 */
    movl    $0, %eax
    leave
    ret

如您所见,在这种情况下,变量地址是作为函数基指针的偏移量来计算的。如果启用优化,变量的值可能会存储在寄存器中。


非常感谢您。您不仅耐心为我解释了内部汇编代码,还满足了我的好奇心,让我想学习汇编语言。向您致敬,先生! - João Silva
只有一件事,如果可以的话,还想问一下。这些偏移量是不是意味着:例如:%ebp -12 = 从基地址开始往后数12个地址? - João Silva
@JoãoSilva 如果%ebp为0xffffcfe8,则c的地址将为0xffffcfe8 - 4 = 0xffffcfdc,如果这是你所问的。 - kharvd
@JoãoSilva 我也推荐阅读这篇文章 http://en.wikipedia.org/wiki/Call_stack - kharvd
@kharvd 你是真的将它编译成汇编了吗,还是只是自己生成了那个ASM?如果是你自己写的ASM,那么你就是一个传奇。 - brettwhiteman
@Brett 我肯定刚刚用了GCC,然后稍微清理了一下。手写这样简单的逻辑汇编语言并不难。 - kharvd

1

所以这有两个部分,我会尽力而为。

在编译时,编译器将把C++代码转换为内部表示形式。然后,它会尽可能高效地使用CPU寄存器,并将其余数据推入RAM中。随着程序的执行,来自RAM的数据将被复制到寄存器中来回传递。

关于您的另一个问题,我见过人们用的一种方法是针对用户拥有的黄金。程序可以获取整个游戏的内存空间并进行复制。然后,用户执行某些操作(最小操作)以获得或失去黄金。外部应用程序随后搜索整个内存空间以查找哪些值已更改,以及先前的黄金数量和当前的黄金数量。一旦他们找到此位置,他们就能够编辑内存位置并将其更新为任何他们想要的值。

通常情况下,游戏越复杂,该方法就越困难。


谢谢你的回答。很抱歉我这么困惑,但请想象一下:int a=5; a=6; 你的第一个解释并没有告诉我程序如何知道要更改哪个值。另一方面,你的第二个答案解释了在内存中搜索值的过程,就像CheatEngine一样。这是我已经知道的。我的问题是关于作弊数据库的,它们保存了看起来像地址的东西,就好像同一个地址每次程序运行时都保存着相同的变量。如果我表达不清楚,请原谅,我的英语并没有帮助到我。 - João Silva
@JoãoSilva:许多系统正在实现地址空间布局随机化,这将使其变得更加困难。 - Bill Lynch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接