【问题标题】:Writing my own C++ Compiler .. stuck on variables编写我自己的 C++ 编译器 .. 卡在变量上
【发布时间】:2012-10-21 14:07:16
【问题描述】:

我目前正在 JS 中为我​​的 Logisim CPU 开发一个 c++ 编译器,现在变量有问题:

我在 ram 中定义了一个空间来存储数据/值,并且我已经定义了一个空间来存储数据空间的地址。我有一个带有指向最后一个变量的指针的寄存器 nx 和一个带有指向最后一个“数据存储”RAM 的指针的寄存器 mx。但我不知道如何访问它们,例如这里:

修改后的 C++ 代码:

int *pointer_test;
int test;
test = 123;
pointer_test = &test;
*pointer_test = 25;

预编译器:

//Allocate new variable       <---  int *pointer_test;
add nx, 1
//Set the pointer pointing to zero
sram nx, 0


//Allocate another variable   <---  int test;
add nx, 1
//Allocate new storage for the variable
add mx, 1

//Let the variable point to the data <--- test = 123;
sram nx, mx
sram mx, 123

我现在如何实现:

pointer_test = &test; 

我只有 &test 的值,保存在 nx 中,因为它是最后声明的变量,但不是变量/指针“pointer_test”的地址 ...

【问题讨论】:

    标签: c++ variables assembly compiler-construction cpu


    【解决方案1】:

    您可能想编写基于堆栈的程序集,就像过去 20 年中的所有其他 C 编译器一样。这意味着 RAM 中有一个称为堆栈的数据区域,它是一个 FIFO 队列,它会向下增长。堆栈也总是至少包含一个寄存器:堆栈指针。堆栈指针指向堆栈中的当前位置,下一件事将去向。因此,要将某些内容添加到堆栈中,请将其放在堆栈指针指向的位置,然后从堆栈指针中减去该内容的大小。

    另一个在汇编中最常使用的来自 C 的寄存器是基指针。基指针指向当前帧的开头。框架可以粗略地与 C 中的范围进行比较。所以,如果我有这段代码:

    int a;
    {
      int b;
    }
    

    栈顶位于 0x9999,然后a 将位于 0x9995(假设 4 字节 int),栈指针现在指向 0x9991,基指针仍指向 0x9999。当进入新的作用域时,基指针移动到栈指针,然后B被放到0x9991处。然后,当退出作用域时,堆栈指针被设置为基指针,有效地擦除了较低作用域中的变量。

    我从未听说过您正在为其编程的体系结构,但只知道任何两个寄存器都可以,但是某些体系结构,例如 x86,具有特定的 stak 寄存器(ebpesp 在 32 位和rebrsp 在 64 位上)。

    但为了回答更多问题,编译器的工作是知道每个变量在堆栈中的偏移量是多少,因此它可以执行以下操作(伪代码):

    base_pointer - 5 (Offset for pointer_test) = base_pointer - 4 (offset for test)
    

    【讨论】:

    • 我认为通常堆栈从0开始并增加,它提供了一种简单的方法来检查它是否为空而不知道它的大小。
    • @J.N.堆栈可以从任何地方开始,因为进程中的多个线程将拥有自己的堆栈,并且所有线程都不能从地址零开始,该地址很可能不在进程地址空间中。但是,如果堆栈数据结构与索引一起使用,它通常会以索引值 0 开始,表示它是空的。
    • @Linuxios 抱歉,我正在写信给 JN。我觉得你的解释很好。
    • @RichardChambers:对不起。我也意识到了这一点并删除了评论!
    • @TobiasSpringer:您需要做的是维护变量名称 (test) 到基指针偏移量的映射。所以堆栈帧中的第一个变量的偏移量为 0,然后是偏移量sizeof(type_of_thing_before),依此类推。注意:如果您维护一个所有内容都相同大小的堆栈会容易得多,因此如果您将除整数、无符号整数和指针之外的所有内容都存储在堆上会很好。