这不是任何一个目的是什么的问题.相反,这是一个问题,谁或什么负责堆栈和堆的发明?
这些C++编译器的发明是什么?
操作系统是否指定RAM中指定为"堆栈"和"堆"的内存部分?
我很确定它们不是内置于硬件中但我可能是错的.
此外,编译器是否负责生成汇编代码,指定哪些本地或函数数据将存储在堆栈与CPU寄存器中?
谁或什么负责堆栈和堆的发明?
就发明堆栈和堆而言,您可以更好地搜索网络.这些概念已存在数十年.
这些C++编译器的发明是什么?
也许发明在这里是错误的术语.它们是数据结构.编译器和OS(如果存在)负责组织和利用存储器.
操作系统是否指定RAM中指定为"堆栈"和"堆"的内存部分?
这是操作系统特定的,可能因操作系统而异.有些操作系统会保留堆栈和堆区域,有些则不会.
在我正在进行的嵌入式系统中,有两个堆区:1)链接器中指定的区域,2)分配给OS的一部分内存.这两个区域都设置为零,所以我们没有任何堆.
堆栈区域由在初始化C语言运行时库之前运行的初始化代码设置.RTL代码也可以创建一些堆栈区域.我们的RTOS还创建堆栈区域(每个任务一个).
因此,没有一个区域称为堆栈.某些平台根本不使用堆栈概念(特别是那些内存容量受到严格限制的平台).
我很确定它们不是内置于硬件中但我可能是错的.
取决于硬件.简单且廉价的硬件仅分配RAM区域(读/写存储器).更复杂和昂贵的硬件可以为堆栈,堆,可执行文件和数据分配单独的区域.常量可以放入ROM(只读存储器,如Flash)中.没有支持所有内容的单一配置或单配置.台式电脑不同的动物小于嵌入式系统.
此外,编译器是否负责生成汇编代码,指定哪些本地或函数数据将存储在堆栈与CPU寄存器中?
任务可以在链接器或编译器中,也可以在两者中.
许多编译器工具链都使用堆栈和CPU寄存器.许多变量和数据可以在堆栈,寄存器,RAM或ROM中.编译器旨在充分利用平台的资源,包括内存和寄存器.
研究的一个很好的例子是编译器生成的汇编语言.另请查看链接器指令文件.寄存器或堆栈存储器的使用如此依赖于数据结构(和类型),它们对于不同的功能可能是不同的.另一个因素是可用的内存量和种类.如果处理器可用的寄存器很少,则编译器可以使用堆栈传递变量.较大的数据(不适合寄存器)可以在堆栈上传递或传递给数据的指针.这里列举的选项和组合太多了.
为了使C和C++语言非常可移植,许多概念被委托给实现(编译器/工具链).其中两个概念通常称为堆栈和堆.C和C++语言标准使用简单模型作为语言环境.此外,还有诸如"托管"和"半托管"之类的术语,表示平台支持语言要求的程度.该栈和堆都没有数据结构需要,以支持的语言由平台.它们确实有助于提高执行效率.
如果支持堆栈和堆,则它们的位置和管理是实现的责任(工具链).编译器可以自由使用它自己的内存管理功能或OS(如果存在).堆栈和堆的管理可能需要硬件支持(例如虚拟内存管理或分页;以及防护).堆栈不需要向堆增长.不需要堆栈以正方向增长.这些都取决于实现(工具链),他们可以实现和定位堆栈,无论他们喜欢什么. 注意:最有可能的是,它们不会将变量放在只读内存中,也不会将堆栈放在内存容量之外.
这篇文章是关于x86上的32位Linux .我不了解其他架构/操作系统.
这些C++编译器的发明是什么?[OS]是否指定RAM中指定为"堆栈"和"堆"的内存部分?
程序有不同的部分,其中一部分是.data
部分.动态内存分配通常使用brk
系统调用(sbrk
在其上构建)来实现.man brk
说如下:
brk()
并sbrk()
更改程序中断的位置,该程序中断定义了进程数据段的结束(即,程序中断是未初始化数据段结束后的第一个位置).增加程序中断会为进程分配内存; 减少休息时间会释放内存.
这意味着"堆"或"免费商店"实际上是该.data
部分.
正如@kfx在对这个答案的评论中所说,没有标准声明malloc
必须使用brk
.使用的实现mmap
也是可能的.来自man mmap
:
该mmap()
函数应在进程的地址空间和内存对象之间建立映射.
这基本上意味着文件(Unix意识形态:"一切都是文件")被映射到内存中.
堆栈也在该.data
部分并向下增长.从技术上讲,x86使您能够定义向下增长的堆栈段,但Linux不使用此功能.不知道为什么.
我很确定它们不是内置于硬件中但我可能是错的.
不,他们不是.段在OS的运行时设置,而不是存储在硬件中.
以下内容来自Linux 4.2.
当MBR跳转到引导加载程序并且引导程序已执行时,将执行此操作(路径为/arch/x86/boot/header.S
):
# Normalize the start address ljmp $BOOTSEG, $start2 start2: movw %cs, %ax movw %ax, %ds movw %ax, %es movw %ax, %ss xorw %sp, %sp
所有这些段寄存器都在$BOOTSEG
这里初始化,即0x7c0
.sp
设置为0x00
.不,esp
因为我们仍处于实模式!
在完成初始化之后,执行跳转到真实内核.段寄存器设置如下:
movw $__BOOT_DS, %cx movw $__BOOT_TSS, %di movl %cr0, %edx orb $X86_CR0_PE, %dl # Protected mode movl %edx, %cr0 # Transition to 32-bit mode .byte 0x66, 0xea # ljmpl opcode 2: .long in_pm32 # offset .word __BOOT_CS # segment ENDPROC(protected_mode_jump) .code32 .section ".text32","ax" GLOBAL(in_pm32) # Set up data segments for flat 32-bit mode movl %ecx, %ds movl %ecx, %es movl %ecx, %fs movl %ecx, %gs movl %ecx, %ss
段寄存器cs
再次设置为内容.
此外,编译器是否负责生成汇编代码,指定哪些本地或函数数据将存储在堆栈与CPU寄存器中?
是.对于函数调用,有不同的调用约定:一些将它们的参数压入堆栈,一些将它们移动到寄存器中.
局部变量也可以用寄存器或堆栈实现.
未经优化的C编译器将参数压入堆栈,调用函数,然后将其弹出("stdcall"调用约定).
它们将堆栈用于局部变量,并与ebp
寄存器结合使用.