C程序中的变量和调用及其在Linux进程地址空间中的对应位置

时间:2019-01-11 11:16:23

标签: c linux linux-kernel

我目前正在学习Linux进程地址空间,并且不确定这些C变量在进程地址空间中的对应位置。

我知道调用一个函数时,会创建一个新框架,其中将包含局部变量和其他函数调用等。

我不确定框架中的指针是什么

我有这个功能:

int main(){
    char *pointer1 = NULL;
    char *pointer2 = (void *)0xDDDDDDDD;
    pointer1 = malloc(80);
    strcpy(pointer1, "Testing..");
    return(0);
}

调用main时,将创建一个新框架。

变量被初始化。

我不确定这些是指针,在哪里:

  • *pointer1对应于进程地址空间中的数据还是文本部分?

  • *pointer2对应于进程地址空间中的数据还是文本部分?

  • NULL0xDDDDDDDD是否属于数据或文本部分?

  • pointer1 = malloc(80)起,它属于堆栈部分吗?

3 个答案:

答案 0 :(得分:0)

首先应该注意,C规范实际上并不要求将局部变量存储在堆栈中,它根本没有指定 automatic 变量的位置。

话虽这么说,变量pointer1pointer2本身的存储很可能由编译器放在堆栈上。当调用main函数时,它们的内存将成为编译器创建的堆栈框架的一部分。

继续,在类似现代PC的系统上,指针实际上只不过是一个简单的无符号整数,其值就是它所指向的地址。用于初始化的值(NULL0xDDDDDDDD)只是简单的整数值。初始化与普通的int变量相同。因此,用于初始化的值实际上并不以“数据”形式存在,而是可以直接在机器代码中编码,并因此存储在“文本”(代码)段中。

最后,对于动态分配,它不会更改pointer1的存储位置。它只是为pointer1分配一个新值是什么。分配的内存位于“堆”上,该“堆”与任何程序节均独立(即不在代码,数据或堆栈段中)。

答案 1 :(得分:0)

正如一些程序员伙计所说,C规范未声明必须放置自动变量的区域。但是通常编译器会增加堆栈以将其容纳在此处。但是,它们可能以.data区域结尾,并且如果例如被定义为static char *pointer1,它们将结束。

初始化值在程序区域中可能存在也可能不存在。在您的情况下,由于值的类型为int,因此,如果可以使用带有适当内联运算符的指令,则大多数体系结构都将内联初始化作为适当的机器指令进行内联。例如,在x86_64中,将发出单个mov / movq操作,以将0(NULL)或另一个int放入堆栈中的适当内存位置。

但是,用全局作用域初始化的变量,例如static char string[40] = "Hello world"或其他初始化的全局变量最终在.data区域上占据了空间。编译器可以改为在.bss区域中放置已声明但未定义的全局范围的变量。

问题由于指针1 = malloc(80),它属于堆栈部分吗?定义不明确,因为它包含两件事。

pointer1是将保存在&pointer1处的值。考虑到以上考虑,编译器可能会将其放在堆栈中的地址。

malloc(80)的结果是一个值,该值引用堆上的一个区域(一个不同的区域),该区域在映射的程序空间之外动态分配。 在Linux上,调用malloc的结果甚至可能创建一个新的以NULL为后盾的内存区域(即,不是永久存储在文件中的过渡区域;尽管它可以被内核交换)。

从本质上讲,您可以想到malloc(80)的行为,就像(不考虑free(),所以这是一个过分的简化):

int space_left = 0; void *last_mapping = NULL;
void *malloc(int req) {
    void *result;
    if (space_left < req) {
        last_mapping = mmap(NULL, MALLOC_CHUNK_LENGTH, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        space_left = MALLOC_CHUNK_LENGTH;
    }
    space_left -= req;
    result = last_mapping;
    last_mapping += req;
    return result;
}

使用MAP_PRIVATE调用mallocmmap之间的巨大区别是mmap是Linux系统调用,它必须进行内核上下文切换,分配新的内存映射并为每个重置MMU层。分配内存块,而malloc可以更智能,并使用单个大区域作为“堆”,并在堆初始化之后在用户空间中管理不同的malloc和free(直到堆空间用完为止,在那里它可能必须管理多个堆) )。

答案 2 :(得分:-1)

您最后一个疑问的部分,即“因为指标1 = malloc(80),它属于堆栈部分吗?”,我可以告诉您

在C语言中,使用某些标准库函数从堆分配动态内存。两个关键的动态内存函数是malloc()和free()。​​

malloc()函数采用单个参数,该参数是请求的内存区域的大小(以字节为单位)。它返回一个指向已分配内存的指针。如果分配失败,则返回NULL。标准库函数的原型是这样的:

      void *malloc(size_t size);

free()函数采用malloc()返回的指针,并取消分配内存。没有返回成功或失败的指示。函数原型如下:

      void free(void *pointer);

您可以参考文档 https://www.design-reuse.com/articles/25090/dynamic-memory-allocation-fragmentation-c.html