Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
获取过程段的开始和结束C/C++;_C_Linux_Unix_Memory Management_System - Fatal编程技术网

获取过程段的开始和结束C/C++;

获取过程段的开始和结束C/C++;,c,linux,unix,memory-management,system,C,Linux,Unix,Memory Management,System,我需要得到以下进程段的开始和结束地址:代码、数据、堆栈、环境。我知道它是如何位于内存中的,但不知道如何使用api调用或其他方法获取它。我发现了如何使用此代码开始一些片段 #include <stdio.h> int temp_data = 100; static int temp_bss; void print_addr ( void ) { int local_var = 100; int *code_segment_address = ( in

我需要得到以下进程段的开始和结束地址:代码、数据、堆栈、环境。我知道它是如何位于内存中的,但不知道如何使用api调用或其他方法获取它。我发现了如何使用此代码开始一些片段

#include <stdio.h>

int temp_data = 100;
static int temp_bss;

void print_addr ( void )
{
        int local_var = 100;
        int *code_segment_address = ( int* ) &print_addr;
        int *data_segment_address = &temp_data;
        int *bss_address = &temp_bss;
        int *stack_segment_address = &local_var;

        printf ( "\nAddress of various segments:" );
        printf ( "\n\tCode Segment : %p" , code_segment_address );
        printf ( "\n\tData Segment : %p" , data_segment_address );
        printf ( "\n\tBSS : %p" , bss_address );
        printf ( "\n\tStack Segment : %p\n" , stack_segment_address );

}

int main ( )
{
        print_addr ();
        return 0;
}
#包括
int temp_数据=100;
静态温度;
作废打印地址(作废)
{
int local_var=100;
整数*代码\段\地址=(整数*)&打印地址;
int*数据段地址=&temp\u数据;
int*bss\u地址=&temp\u bss;
int*stack_segment_address=&local_var;
printf(“\n不同段的地址:”);
printf(“\n\t代码段:%p”,代码段地址);
printf(“\n\t数据段:%p”,数据段地址);
printf(“\n\tBSS:%p”,bss\u地址);
printf(“\n\t堆栈段:%p\n”,堆栈段地址);
}
int main()
{
打印地址();
返回0;
}
但我不知道如何找到每个片段的结尾。我唯一的想法是,一段的结束就是另一段的开始。
请解释如何使用C和linux API实现这一点。

我不确定数据或堆段是否定义良好且唯一(特别是在多线程应用程序中,或者只是在使用动态库的应用程序中,包括
libc.so
)。换句话说,不再有任何定义良好的文本、数据或堆段的开始和结束,因为今天一个进程有许多这样的段。所以你的问题在一般情况下都没有意义

大多数
malloc
实现使用和
munmap
sbrk

你应该多读一点。特别是,您的应用程序可以读取
/proc/self/maps
(或
/proc/1234/maps
用于pid 1234的过程)或
/proc/self/smap
;尝试<代码> CAT/PROC/MUL/MAP/<代码>,并考虑使用“<代码>”/PROC/MUI/MAP > <代码>(然后在代码<循环> FEX< <代码>或<代码> RealLoad ,最后并快速<代码> fCuts)。也许是相关的

您还可以读取程序的标题,例如
/proc/self/exe
。另请参见和&&&&。也要读书和读书

另请参见相关问题(和)。请注意,最近的Linux系统都有,因此在同一环境中运行同一程序的两个类似进程的地址布局会有所不同


还可以尝试使用一些简单的命令或程序。你会更了解相关内容。另请阅读

正如另一篇评论中所说,文本、数据和堆栈段的概念在今天的Linux上并不存在。程序文本分布在共享库中,内存分配由
mmap()
完成,而不是
brk()
导致分配的数据分布在程序的整个地址空间中

也就是说,您可以使用
brk()
系统调用来查找数据段的结尾,也可以使用符号
etext
edata
end
来查找可执行文件的边界。文本段的开头通常是固定的(也称为“加载地址”),并取决于体系结构和链接器配置。请注意,您的程序很可能会在二进制文件的文本部分之外执行代码,并且很可能不会使用brk分配任何动态内存


有关更多详细信息,请参阅相应的手册页。

有关帮助,请参阅
man 3 end

#include <stdio.h>
extern etext;
extern edata;
extern end;
int
main(int ac, char **av, char **env)
{
        printf("main %p\n", main);
        printf("etext %p\n", &etext);
        printf("edata %p\n", &edata);
        printf("end %p\n", &end);
        return 0;
}
#包括
外部文本;
外部教育;
外端;
int
主(内部ac、字符**av、字符**env)
{
printf(“主%p\n”,主);
printf(“etext%p\n”和&etext);
printf(“edata%p\n”和&edata);
printf(“结束%p\n”,&end);
返回0;
}
这3个符号的地址是文本、初始化数据和未初始化数据段末尾后的第一个地址

您可以通过
main()
的第三个参数获取enivonment变量,如上面的示例代码所示,但也可以从地址
&argv[0]
开始向上遍历堆栈。在指向命令行参数字符串的最后一个指针之后有一个空值字(32或64位,具体取决于CPU)。然后是环境

栈顶几乎不可能通过编程实现——现代操作系统都会进行“地址空间布局随机化”(ASLR),以减轻缓冲区溢出。堆栈的“结束”是模糊的,因为您可以在堆栈上进行分配(通过递归或
alloca()
),直到运行到堆的顶部。因此,堆栈的“结束”取决于相关程序的分配模式


你也应该注意ELF辅助向量。请参见
mangetauxval
,了解C语言接口和一些解释。用户程序从来没有使用ELF辅助向量,但它与动态链接密切相关。

当前的Windows和Linux使用平面地址空间,这意味着代码和数据段是相同的,并且几乎总是从0到2^32-1(对于32位系统)和2^64-1(对于64位系统)。除了共享内存之外,不同的进程通常具有完全不同的地址空间。通常只有地址空间的某些部分有映射到它的内存,并且由于硬件限制,某些部分甚至可能无法寻址

链接器的代码和数据段成为可运行映像的一部分,而Linux下常见的ELF格式又增加了一些更复杂的问题。Access是高度特定于OS的,因此不是真正的C++问题。 在Windows下,您可以通过GetModuleHandle(0)获取指向加载映像开始的指针。通过遍历可执行文件头,您可以找到COFF section表,该表允许您将作为映射的可执行文件映像的一部分的所有地址反向映射到它们的地址