首页 > 解决方案 > 以下对象存储在内存中的什么位置?

问题描述

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define TEXT "Good luck on this test"
int main () {
  char* cPtr = (char*)malloc(sizeof(TEXT));
  strncpy(cPtr,TEXT,sizeof(TEXT));
  printf("%s\n",cPtr);
  free(cPtr);
  return(EXIT_SUCCESS);
}
  1. 变量的内存cPtr
  2. 地址指向哪个cPtr
  3. 的代码malloc()
  4. malloc()调用以移动运行该程序的进程的brk 指针的代码?

我想这是:

  1. 数据段
  2. 共享库内存

这是对的吗?

标签: c

解决方案


这实际上是一个领先的问题,因为它假定一切都将在内存中。

局部变量以及没有名称的临时值,仅在必要时才放入堆栈。可能有必要这样做的原因有很多,例如:

  • 编译器是愚蠢的或通过在可能的最低优化级别进行编译而变得愚蠢。
  • 目标机器的架构很奇怪,没有(或很少)寄存器(很少见)。
  • 有太多的局部变量和临时值同时存在,无法将它们全部放入程序中的寄存器中,因此其中一些会“溢出”。溢出并不是一个变量的属性,而是一个特定的生命范围。因此,在某种意义上,一个变量可以四处移动(如果它有多个关联的生存范围并且它们的分配方式不同),甚至可以同时位于多个位置(取决于您如何计算临时副本,或者在涉及循环展开时明确)。
  • 获取和使用局部变量的地址的方式使得编译器无法证明该变量不需要在内存中(可能会导致生存范围拆分,因此该变量实际上只是暂时在内存中)。

很可能以上都不适用(最后一项肯定不适用,地址没有被占用)所以我们应该期望cPtr在寄存器中度过它的整个生命周期。

在面向 x64的clang上对其进行测试,我们可能会得到如下代码:

main:                                   # @main
    push    rbx
    mov     edi, 23
    call    malloc
    mov     rbx, rax

    ; at this point, rbx roughly corresponds to cPtr
    ; it's also still in rax but rax is overwritten by the next operation

    movabs  rax, 32777976875610985 ; btw this weird number is a piece of string
    mov     qword ptr [rbx + 15], rax
    movups  xmm0, xmmword ptr [rip + .L.str]
    movups  xmmword ptr [rbx], xmm0

    ; rbx (cPtr) is copied to rdi in order to give it to puts as argument

    mov     rdi, rbx
    call    puts
    mov     rdi, rbx
    call    free
    xor     eax, eax
    pop     rbx
    ret
.L.str:
    .asciz  "Good luck on this test"

以 MIPS 或 ARM 或 PowerPC 为目标,例如 GCC 显示出类似的模式,即cPtr不在堆栈上而是在一个寄存器中(或多个寄存器,取决于您的计数方式),当然代码看起来非常不同。

上面代码的一个有趣细节是,虽然整个字符串确实出现在数据段(rodata)中,但它的一部分也作为 . 的直接操作数出现在代码段中movabs


推荐阅读