C++ 计算机程序运行时会发生什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5162580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:33:54  来源:igfitidea点击:

What happens when a computer program runs?

c++memoryoperating-systemx86computer-architecture

提问by gaijinco

I know the general theory but I can't fit in the details.

我知道一般理论,但我无法适应细节。

I know that a program resides in the secondary memory of a computer. Once the program begins execution it is entirely copied to the RAM. Then the processor retrive a few instructions (it depends on the size of the bus) at a time, puts them in registers and executes them.

我知道程序驻留在计算机的辅助存储器中。一旦程序开始执行,它就会被完全复制到 RAM 中。然后处理器一次检索一些指令(这取决于总线的大小),将它们放入寄存器并执行它们。

I also know that a computer program uses two kinds of memory: stack and heap, which are also part of the primary memory of the computer. The stack is used for non-dynamic memory, and the heap for dynamic memory (for example, everything related to the newoperator in C++)

我也知道一个计算机程序使用两种内存:堆栈和堆,它们也是计算机主内存的一部分。堆栈用于非动态内存,堆用于动态内存(例如,与newC++ 中的运算符相关的所有内容)

What I can't understand is how those two things connect. At what point is the stack used for the execution of the instructions? Instructions go from the RAM, to the stack, to the registers?

我无法理解的是这两件事是如何联系在一起的。堆栈在什么时候用于执行指令?指令从 RAM 到堆栈,再到寄存器?

回答by Sdaz MacSkibbons

It really depends on the system, but modern OSes with virtual memorytend to load their process images and allocate memory something like this:

这实际上取决于系统,但具有虚拟内存的现代操作系统倾向于加载其进程映像并分配内存,如下所示:

+---------+
|  stack  |  function-local variables, return addresses, return values, etc.
|         |  often grows downward, commonly accessed via "push" and "pop" (but can be
|         |  accessed randomly, as well; disassemble a program to see)
+---------+
| shared  |  mapped shared libraries (C libraries, math libs, etc.)
|  libs   |
+---------+
|  hole   |  unused memory allocated between the heap and stack "chunks", spans the
|         |  difference between your max and min memory, minus the other totals
+---------+
|  heap   |  dynamic, random-access storage, allocated with 'malloc' and the like.
+---------+
|   bss   |  Uninitialized global variables; must be in read-write memory area
+---------+
|  data   |  data segment, for globals and static variables that are initialized
|         |  (can further be split up into read-only and read-write areas, with
|         |  read-only areas being stored elsewhere in ROM on some systems)
+---------+
|  text   |  program code, this is the actual executable code that is running.
+---------+

This is the general process address space on many common virtual-memory systems. The "hole" is the size of your total memory, minus the space taken up by all the other areas; this gives a large amount of space for the heap to grow into. This is also "virtual", meaning it maps to your actualmemory through a translation table, and may be actually stored at any location in actual memory. It is done this way to protect one process from accessing another process's memory, and to make each process think it's running on a complete system.

这是许多常见虚拟内存系统上的通用进程地址空间。“洞”是你的总内存大小,减去所有其他区域占用的空间;这为堆增长提供了大量空间。这也是“虚拟的”,意味着它通过一个转换表映射到您的实际内存中,并且可能实际存储在实际内存中的任何位置。这样做是为了防止一个进程访问另一个进程的内存,并使每个进程都认为它在一个完整的系统上运行。

Note that the positions of, e.g., the stack and heap may be in a different order on some systems (see Billy O'Neal's answerbelow for more details on Win32).

请注意,例如,堆栈和堆的位置在某些系统上可能具有不同的顺序(有关 Win32 的更多详细信息,请参阅下面的Billy O'Neal 的回答)。

Other systems can be verydifferent. DOS, for instance, ran in real mode, and its memory allocation when running programs looked much differently:

其他系统可能非常不同。例如,DOS 以实模式运行,它在运行程序时的内存分配看起来大不相同:

+-----------+ top of memory
| extended  | above the high memory area, and up to your total memory; needed drivers to
|           | be able to access it.
+-----------+ 0x110000
|  high     | just over 1MB->1MB+64KB, used by 286s and above.
+-----------+ 0x100000
|  upper    | upper memory area, from 640kb->1MB, had mapped memory for video devices, the
|           | DOS "transient" area, etc. some was often free, and could be used for drivers
+-----------+ 0xA0000
| USER PROC | user process address space, from the end of DOS up to 640KB
+-----------+
|command.com| DOS command interpreter
+-----------+ 
|    DOS    | DOS permanent area, kept as small as possible, provided routines for display,
|  kernel   | *basic* hardware access, etc.
+-----------+ 0x600
| BIOS data | BIOS data area, contained simple hardware descriptions, etc.
+-----------+ 0x400
| interrupt | the interrupt vector table, starting from 0 and going to 1k, contained 
|  vector   | the addresses of routines called when interrupts occurred.  e.g.
|  table    | interrupt 0x21 checked the address at 0x21*4 and far-jumped to that 
|           | location to service the interrupt.
+-----------+ 0x0

You can see that DOS allowed direct access to the operating system memory, with no protection, which meant that user-space programs could generally directly access or overwrite anything they liked.

你可以看到 DOS 允许直接访问操作系统内存,没有保护,这意味着用户空间程序通常可以直接访问或覆盖他们喜欢的任何东西。

In the process address space, however, the programs tended to look similar, only they were described as code segment, data segment, heap, stack segment, etc., and it was mapped a little differently. But most of the general areas were still there.

然而,在进程地址空间中,程序往往看起来相似,只是它们被描述为代码段、数据段、堆、堆栈段等,并且映射方式略有不同。但大部分一般区域仍然存在。

Upon loading the program and necessary shared libs into memory, and distributing the parts of the program into the right areas, the OS begins executing your process wherever its main method is at, and your program takes over from there, making system calls as necessary when it needs them.

将程序和必要的共享库加载到内存中,并将程序的各个部分分配到正确的区域后,操作系统开始在其主要方法所在的任何地方执行您的进程,并且您的程序从那里接管,在必要时进行系统调用它需要他们。

Different systems (embedded, whatever) may have very different architectures, such as stackless systems, Harvard architecture systems (with code and data being kept in separate physical memory), systems which actually keep the BSS in read-only memory (initially set by the programmer), etc. But this is the general gist.

不同的系统(嵌入式,无论如何)可能有非常不同的架构,例如无堆栈系统、哈佛架构系统(代码和数据保存在单独的物理内存中)、实际上将 BSS 保存在只读内存中的系统(最初由程序员)等。但这是一般要点。



You said:

你说:

I also know that a computer program uses two kinds of memory: stack and heap, which are also part of the primary memory of the computer.

我也知道一个计算机程序使用两种内存:堆栈和堆,它们也是计算机主内存的一部分。

"Stack" and "heap" are just abstract concepts, rather than (necessarily) physically distinct "kinds" of memory.

“堆栈”和“堆”只是抽象概念,而不是(必然)物理上不同的“种类”内存。

A stackis merely a last-in, first-out data structure. In the x86 architecture, it can actually be addressed randomly by using an offset from the end, but the most common functions are PUSH and POP to add and remove items from it, respectively. It is commonly used for function-local variables (so-called "automatic storage"), function arguments, return addresses, etc. (more below)

堆栈仅仅是后进先出的数据结构。在 x86 架构中,它实际上可以通过使用从末尾的偏移量来随机寻址,但最常见的功能是 PUSH 和 POP 分别向其中添加和删除项目。它通常用于函数局部变量(所谓的“自动存储”)、函数参数、返回地址等(更多见下文)

A "heap"is just a nickname for a chunk of memory that can be allocated on demand, and is addressed randomly (meaning, you can access any location in it directly). It is commonly used for data structures that you allocate at runtime (in C++, using newand delete, and mallocand friends in C, etc).

一个“堆”仅仅是一个内存块,也可以根据需要分配一个昵称,并随机寻址(意思,你可以直接访问任何位置)。它通常用于您在运行时分配的数据结构(在 C++ 中,使用newand delete,以及mallocC 中的和朋友等)。

The stack and heap, on the x86 architecture, both physically reside in your system memory (RAM), and are mapped through virtual memory allocation into the process address space as described above.

x86 架构上的堆栈和堆都物理地驻留在系统内存 (RAM) 中,并通过虚拟内存分配映射到进程地址空间,如上所述。

The registers(still on x86), physically reside inside the processor (as opposed to RAM), and are loaded by the processor, from the TEXT area (and can also be loaded from elsewhere in memory or other places depending on the CPU instructions that are actually executed). They are essentially just very small, very fast on-chip memory locations that are used for a number of different purposes.

寄存器(仍然在x86),物理驻留处理器(与RAM)内,并且由处理器加载,从文本区(并且也可以从其它地方的存储器或其他地方被加载根据CPU指令实际执行)。它们本质上只是非常小、速度非常快的片上存储器位置,可用于多种不同的目的。

Register layout is highly dependent on the architecture (in fact, registers, the instruction set, and memory layout/design, are exactly what is meant by "architecture"), and so I won't expand upon it, but recommend you take an assembly language course to understand them better.

寄存器布局高度依赖于体系结构(实际上,寄存器、指令集和内存布局/设计正是“体系结构”的含义),因此我不会对其进行扩展,但建议您采用汇编语言课程以更好地理解它们。



Your question:

你的问题:

At what point is the stack used for the execution of the instructions? Instructions go from the RAM, to the stack, to the registers?

堆栈在什么时候用于执行指令?指令从 RAM 到堆栈,再到寄存器?

The stack (in systems/languages that have and use them) is most often used like this:

堆栈(在拥有并使用它们的系统/语言中)最常使用如下:

int mul( int x, int y ) {
    return x * y;       // this stores the result of MULtiplying the two variables 
                        // from the stack into the return value address previously 
                        // allocated, then issues a RET, which resets the stack frame
                        // based on the arg list, and returns to the address set by
                        // the CALLer.
}

int main() {
    int x = 2, y = 3;   // these variables are stored on the stack
    mul( x, y );        // this pushes y onto the stack, then x, then a return address,
                        // allocates space on the stack for a return value, 
                        // then issues an assembly CALL instruction.
}

Write a simple program like this, and then compile it to assembly (gcc -S foo.cif you have access to GCC), and take a look. The assembly is pretty easy to follow. You can see that the stack is used for function local variables, and for calling functions, storing their arguments and return values. This is also why when you do something like:

像这样写一个简单的程序,然后编译成汇编(gcc -S foo.c如果你有GCC权限的话),看看。组装很容易遵循。您可以看到堆栈用于函数局部变量,以及用于调用函数、存储它们的参数和返回值。这也是为什么当您执行以下操作时:

f( g( h( i ) ) ); 

All of these get called in turn. It's literally building up a stack of function calls and their arguments, executing them, and then popping them off as it winds back down (or up ;). However, as mentioned above, the stack (on x86) actually resides in your process memory space (in virtual memory), and so it can be manipulated directly; it's not a separate step during execution (or at least is orthogonal to the process).

所有这些都被依次调用。它实际上是建立一堆函数调用及其参数,执行它们,然后在它回落(或向上;)时将它们弹出。但是,如上所述,堆栈(在 x86 上)实际上驻留在您的进程内存空间(在虚拟内存中),因此可以直接操作;它不是执行期间的单独步骤(或至少与流程正交)。

FYI, the above is the C calling convention, also used by C++. Other languages/systems may push arguments onto the stack in a different order, and some languages/platforms don't even use stacks, and go about it in different ways.

仅供参考,以上是C 调用约定,也被 C++ 使用。其他语言/系统可能会以不同的顺序将参数推送到堆栈上,有些语言/平台甚至不使用堆栈,而是以不同的方式进行处理。

Also note, these aren't actual lines of C code executing. The compiler has converted them into machine language instructions in your executable. They are then (generally) copied from the TEXT area into the CPU pipeline, then into the CPU registers, and executed from there.[This was incorrect. See Ben Voigt's correctionbelow.]

另请注意,这些不是实际执行的 C 代码行。编译器已将它们转换为可执行文件中的机器语言指令。 然后(通常)将它们从 TEXT 区域复制到 CPU 管道中,然后复制到 CPU 寄存器中,并从那里执行。[这是不正确的。请参阅下面的Ben Voigt 的更正。]

回答by Ben Voigt

Sdaz has gotten a remarkable number of upvotes in a very short time, but sadly is perpetuating a misconception about how instructions move through the CPU.

Sdaz 在很短的时间内获得了大量的赞成票,但遗憾的是,它对指令如何通过 CPU 移动存在误解。

The question asked:

问的问题是:

Instructions go from the RAM, to the stack, to the registers?

指令从 RAM 到堆栈,再到寄存器?

Sdaz said:

斯达兹说:

Also note, these aren't actual lines of C code executing. The compiler has converted them into machine language instructions in your executable. They are then (generally) copied from the TEXT area into the CPU pipeline, then into the CPU registers, and executed from there.

另请注意,这些不是实际执行的 C 代码行。编译器已将它们转换为可执行文件中的机器语言指令。然后(通常)将它们从 TEXT 区域复制到 CPU 管道中,然后复制到 CPU 寄存器中,并从那里执行。

But this is wrong. Except for the special case of self-modifying code, instructions never enter the datapath. And they are not, cannot be, executed from the datapath.

但这是错误的。除了自修改代码的特殊情况外,指令从不进入数据通路。它们不是也不能从数据路径执行。

The x86 CPU registersare:

x86的CPU寄存器是:

  • General registers EAX EBX ECX EDX

  • Segment registers CS DS ES FS GS SS

  • Index and pointers ESI EDI EBP EIP ESP

  • Indicator EFLAGS

  • 通用寄存器 EAX EBX ECX EDX

  • 段寄存器 CS DS ES FS GS SS

  • 索引和指针 ESI EDI EBP EIP ESP

  • 指示符 EFLAGS

There are also some floating-point and SIMD registers, but for the purposes of this discussion we'll classify those as part of the coprocessor and not the CPU. The memory-management unit inside the CPU also has some registers of its own, we'll again treat that as a separate processing unit.

还有一些浮点和 SIMD 寄存器,但出于本次讨论的目的,我们将它们归类为协处理器的一部分,而不是 CPU。CPU 内部的内存管理单元也有一些自己的寄存器,我们将再次将其视为一个单独的处理单元。

None of these registers are used for executable code. EIPcontains the address of the executing instruction, not the instruction itself.

这些寄存器均不用于可执行代码。 EIP包含执行指令的地址,而不是指令本身。

Instructions go through a completely different path in the CPU from data (Harvard architecture). All current machines are Harvard architecture inside the CPU. Most these days are also Harvard architecture in the cache. x86 (your common desktop machine) are Von Neumann architecture in the main memory, meaning data and code are intermingled in RAM. That's beside the point, since we're talking about what happens inside the CPU.

指令在 CPU 中通过与数据完全不同的路径(哈佛架构)。目前所有的机器CPU内部都是哈佛架构。这些天大多数也是缓存中的哈佛架构。x86(您常见的台式机)是主内存中的冯诺依曼架构,这意味着数据和代码混合在 RAM 中。这不是重点,因为我们谈论的是 CPU 内部发生的事情。

The classic sequence taught in computer architecture is fetch-decode-execute. The memory controller looks up the instruction stored at the address EIP. The bits of the instruction go through some combinational logic to create all the control signals for the different multiplexers in the processor. And after some cycles, the arithmetic logic unit arrives at a result, which is clocked into the destination. Then the next instruction is fetched.

计算机体系结构中教授的经典顺序是获取-解码-执行。内存控制器查找存储在地址 处的指令EIP。指令的位通过一些组合逻辑为处理器中的不同多路复用器创建所有控制信号。并且在一些周期之后,算术逻辑单元到达一个结果,该结果被计时到目的地。然后取出下一条指令。

On a modern processor, things work a little differently. Each incoming instruction is translated into a whole series of microcode instructions. This enable pipelining, because the resources used by the first microinstruction aren't needed later, so they can begin working on the first microinstruction from the next instruction.

在现代处理器上,工作方式略有不同。每条传入指令都被翻译成一系列微码指令。这将启用流水线,因为第一条微指令使用的资源稍后不需要,因此它们可以从下一条指令开始处理第一条微指令。

To top it off, terminology is slightly confused because registeris an electrical engineering term for a collection of D-flipflops. And instructions (or especially microinstructions) may very well be stored temporarily in such a collection of D-flipflops. But this is not what is meant when a computer scientist or software engineer or run-of-the-mill developer uses the term register. They mean the datapath registers as listed above, and these are not used for transporting code.

最重要的是,术语有点混乱,因为寄存器是一组 D 触发器的电气工程术语。指令(或特别是微指令)很可能临时存储在这样的 D 触发器集合中。但是当计算机科学家、软件工程师或普通开发人员使用术语register时,这不是什么意思。它们表示上面列出的数据路径寄存器,它们不用于传输代码。

The names and number of datapath registers vary for other CPU architectures, such as ARM, MIPS, Alpha, PowerPC, but all of them execute instructions without passing them through the ALU.

其他 CPU 架构(例如 ARM、MIPS、Alpha、PowerPC)的数据路径寄存器的名称和数量各不相同,但它们都执行指令而不通过 ALU。

回答by Billy ONeal

The exact layout of the memory while a process is executing is completely dependent on the platform which you're using. Consider the following test program:

进程执行时内存的确切布局完全取决于您使用的平台。考虑以下测试程序:

#include <stdlib.h>
#include <stdio.h>

int main()
{
    int stackValue = 0;
    int *addressOnStack = &stackValue;
    int *addressOnHeap = malloc(sizeof(int));
    if (addressOnStack > addressOnHeap)
    {
        puts("The stack is above the heap.");
    }
    else
    {
        puts("The heap is above the stack.");
    }
}

On Windows NT (and it's children), this program is going to generally produce:

在 Windows NT(和它的孩子)上,这个程序通常会产生:

The heap is above the stack

堆在堆栈之上

On POSIX boxes, it's going to say:

在 POSIX 盒子上,它会说:

The stack is above the heap

栈在堆之上

The UNIX memory model is quite well explained here by @Sdaz MacSkibbons, so I won't reiterate that here. But that is not the only memory model. The reason POSIX requires this model is the sbrksystem call. Basically, on a POSIX box, to get more memory, a process merely tells the Kernel to move the divider between the "hole" and the "heap" further into the "hole" region. There is no way to return memory to the operating system, and the operating system itself does not manage your heap. Your C runtime library has to provide that (via malloc).

@Sdaz MacSkibbons 在这里很好地解释了 UNIX 内存模型,所以我不会在这里重申。但这并不是唯一的内存模型。POSIX 需要这个模型的原因是sbrk系统调用。基本上,在 POSIX 盒子上,为了获得更多内存,进程只是告诉内核将“洞”和“堆”之间的分隔线进一步移入“洞”区域。没有办法将内存返还给操作系统,操作系统本身并不管理你的堆。您的 C 运行时库必须提供(通过 malloc)。

This also has implications for the kind of code actually used in POSIX binaries. POSIX boxes (almost universally) use the ELF file format. In this format, the operating system is responsible for communications between libraries in different ELF files. Therefore, all the libraries use position-independent code (That is, the code itself can be loaded into different memory addresses and still operate), and all calls between libraries are passed through a lookup table to find out where control needs to jump for cross library function calls. This adds some overhead and can be exploited if one of the libraries changes the lookup table.

这也对 POSIX 二进制文件中实际使用的代码类型有影响。POSIX 框(几乎普遍)使用 ELF 文件格式。在这种格式中,操作系统负责不同 ELF 文件中的库之间的通信。因此,所有的库都使用位置无关代码(即代码本身可以加载到不同的内存地址并仍然运行),所有库之间的调用都是通过一个查找表来找出控制需要跳转到哪里进行交叉库函数调用。这会增加一些开销,并且可以在库之一更改查找表时加以利用。

Windows' memory model is different because the kind of code it uses is different. Windows uses the PE file format, which leaves the code in position-dependent format. That is, the code depends on where exactly in virtual memory the code is loaded. There is a flag in the PE spec which tells the OS where exactly in memory the library or executable would like to be mapped when your program runs. If a program or library cannot be loaded at it's preferred address, the Windows loader must rebasethe library/executable -- basically, it moves the position-dependent code to point at the new positions -- which doesn't require lookup tables and cannot be exploited because there's no lookup table to overwrite. Unfortunately, this requires very complicated implementation in the Windows loader, and does have considerable startup time overhead if an image needs to be rebased. Large commercial software packages often modify their libraries to start purposely at different addresses to avoid rebasing; windows itself does this with it's own libraries (e.g. ntdll.dll, kernel32.dll, psapi.dll, etc. -- all have different start addresses by default)

Windows 的内存模型不同,因为它使用的代码类型不同。Windows 使用 PE 文件格式,该格式将代码保留为位置相关格式。也就是说,代码取决于代码加载到虚拟内存中的确切位置。PE 规范中有一个标志,它告诉操作系统在程序运行时库或可执行文件在内存中的确切位置。如果程序或库无法在其首选地址加载,则 Windows 加载程序必须变基库/可执行文件——基本上,它移动依赖于位置的代码指向新位置——它不需要查找表并且不能被利用,因为没有查找表可以覆盖。不幸的是,这需要在 Windows 加载器中实现非常复杂的实现,并且如果需要重新定位图像,则确实会产生相当大的启动时间开销。大型商业软件包经常修改它们的库,故意在不同的地址启动,以避免 rebase;windows本身使用它自己的库(例如ntdll.dll、kernel32.dll、psapi.dll等——默认情况下都有不同的起始地址)来做到这一点

On Windows, virtual memory is obtained from the system via a call to VirtualAlloc, and it is returned to the system via VirtualFree(Okay, technically VirtualAlloc farms out to NtAllocateVirtualMemory, but that's an implementation detail) (Contrast this to POSIX, where memory cannot be reclaimed). This process is slow (and IIRC, requires that you allocate in physical page sized chunks; typically 4kb or more). Windows also provides it's own heap functions (HeapAlloc, HeapFree, etc.) as part of a library known as RtlHeap, which is included as a part of Windows itself, upon which the C runtime (that is, mallocand friends) is typically implemented.

在 Windows 上,虚拟内存是通过调用VirtualAlloc从系统获得的,然后通过VirtualFree返回给系统(好吧,从技术上讲,VirtualAlloc 输出到 NtAllocateVirtualMemory,但这是一个实现细节)(将此与 POSIX 进行对比,其中内存不能被回收)。这个过程很慢(并且 IIRC 要求您分配物理页面大小的块;通常为 4kb 或更多)。Windows 还提供它自己的堆函数(HeapAlloc、HeapFree 等)作为称为 RtlHeap 的库的一部分,该库作为 Windows 本身的一部分包含在内,通常在其上实现 C 运行时(即malloc和朋友)。

Windows also has quite a few legacy memory allocation APIs from the days when it had to deal with old 80386s, and these functions are now built on top of RtlHeap. For more information about the various APIs that control memory management in Windows, see this MSDN article: http://msdn.microsoft.com/en-us/library/ms810627.

从 Windows 必须处理旧的 80386 的日子开始,Windows 也有很多遗留的内存分配 API,现在这些函数构建在 RtlHeap 之上。有关在 Windows 中控制内存管理的各种 API 的详细信息,请参阅此 MSDN 文章:http: //msdn.microsoft.com/en-us/library/ms810627

Note also that this means on Windows a single process an (and usually does) have more than one heap. (Typically, each shared library creates it's own heap.)

还要注意,这意味着在 Windows 上,单个进程(通常确实)有多个堆。(通常,每个共享库都会创建自己的堆。)

(Most of this information comes from "Secure Coding in C and C++" by Robert Seacord)

(大部分信息来自 Robert Seacord 的“C 和 C++ 中的安全编码”)

回答by vbence

The stack

堆栈

In X86 architercture the CPU executes operations with registers. The stack is only used for convenience reasons. You can save the content of your registers to stack before calling a subroutine or a system function and then load them back to continue your operation where you left. (You could to it manually without the stack, but it is a frequently used function so it has CPU support). But you can do pretty much anything without the stack in a PC.

在 X86 架构中,CPU 使用寄存器执行操作。堆栈仅用于方便的原因。您可以在调用子程序或系统函数之前将寄存器的内容保存到堆栈中,然后将它们加载回来以继续您离开的操作。(您可以在没有堆栈的情况下手动使用它,但它是一个经常使用的函数,因此它具有 CPU 支持)。但是在 PC 中没有堆栈你几乎可以做任何事情。

For example an integer multiplication:

例如整数乘法:

MUL BX

Multiplies AX register with BX register. (The result will be in DX and AX, DX containing the higher bits).

将 AX 寄存器与 BX 寄存器相乘。(结果将在 DX 和 AX 中,DX 包含较高位)。

Stack based machines (like JAVA VM) use the stack for their basic operations. The above multiplication:

基于堆栈的机器(如 JAVA VM)使用堆栈进行基本操作。上面的乘法:

DMUL

This pops two values from the top of the stack and multiplies tem, then pushes the result back to the stack. Stack is essential for this kind of machines.

这会从堆栈顶部弹出两个值并乘以 tem,然后将结果推回堆栈。堆栈对于这种机器是必不可少的。

Some higher level programming languages (like C and Pascal) use this later method for passing parameters to functions: the parameters are pushed to the stack in left to right order and popped by the function body and the return values are pushed back. (This is a choice that the compiler manufacturers make and kind of abuses the way the X86 uses the stack).

一些更高级的编程语言(如 C 和 Pascal)使用后面的方法将参数传递给函数:参数按从左到右的顺序推入堆栈,由函数体弹出,返回值被推回。(这是编译器制造商做出的一种选择,并且有点滥用 X86 使用堆栈的方式)。

The heap

The heap is an other concept that exists only in the realm of the compilers. It takes the pain of handling the memory behind your variables away, but it is not a function of the CPU or the OS, it is just a choice of housekeeping the memory block wich is given out by the OS. You could do this manyually if you want.

堆是另一个仅存在于编译器领域的概念。它消除了处理变量背后的内存的痛苦,但它不是 CPU 或操作系统的功能,它只是对操作系统发出的内存块进行管理的一种选择。如果你愿意,你可以多次这样做。

Accessing system resources

访问系统资源

The operating system has a public interface how you can access its functions. In DOS parameters are passed in registers of the CPU. Windows uses the stack for passing parameters for OS functions (the Windows API).

操作系统有一个公共接口,您可以如何访问其功能。在 DOS 中,参数在 CPU 的寄存器中传递。Windows 使用堆栈为 OS 函数(Windows API)传递参数。