基础知识
一、实验预习
1.代码运行的步骤
编写源代码:首先,你需要编写程序的源代码文件,可以使用C、C++、汇编语言或其他支持的编程语言。假设你的源代码文件是hello.c。
预处理:可以选择对源代码进行预处理,例如处理宏定义、条件编译等。预处理器通常由编译器自动调用,你只需要执行编译命令即可。
编译:使用编译器将源代码文件编译为汇编语言或目标代码文件。
2.ELF基础知识
ELF文件结构:ELF是一种二进制文件格式,用于存储可执行程序、共享库和目标文件。它由多个段(Sections)和节(Segments)组成,包括代码段、数据段、符号表段等。每个段和节都有特定的功能和属性。
ELF头部(ELF Header):ELF文件的开头是一个特殊的段,称为ELF头部。ELF头部包含了关于文件的基本信息,如文件类型、机器架构、入口点地址、段表偏移等。
段(Sections):ELF文件中的段用于组织和存储不同类型的数据。常见的段包括代码段(.text)、数据段(.data)、只读数据段(.rodata)、符号表段(.symtab)等。每个段都有自己的标志和属性。
节(Segments):ELF文件中的节是一种逻辑组织方式,用于链接和加载。节可以包含一个或多个段。常见的节包括代码节(.text)、数据节(.data)、只读数据节(.rodata)、字符串表节(.strtab)等。
符号表(Symbol Table):ELF文件中的符号表用于存储程序中定义和引用的函数、变量和其他符号的信息。符号表包含符号名称、类型、大小、地址等信息,可以用于符号解析和调试。
静态链接与动态链接:ELF文件支持动态链接,允许多个程序共享同一个库文件。动态链接器在运行时将共享库加载到内存中,并解析符号引用。静态链接是在生成可执行文件时进行的。在目标模块中记录符号地址,而在可执行文件中改写为指令直接使用的数字地址。
二、实验过程
1.编译运行测试
采取给test函数增加exec函数的方法,进行调试编译
exec函数如下:
int Exec(int argc, char *argv[])
{
int pid;
/* fork another process */
pid = fork();
if (pid < 0)
{
/* error occurred */
fprintf(stderr,"Fork Failed!");
exit(-1);
}
else if (pid == 0)
{
/* child process */
printf("This is Child Process!\n");
execlp("/hello","hello",NULL);
}
else
{
/* parent process */
printf("This is Parent Process!\n");
/* parent will wait for the child to complete*/
wait(NULL);
printf("Child Complete!\n");
}
}
在main函数里增加一句代码:
MenuConfig("exec","Execute a program",Exec);
增加完后修改test函数,实现exec功能如下图所示。
按照如下代码运行编译:
cd ~/LinuxKernel
vim test.c
cd menu
make rootfs
cd ~/LinuxKernel
rm menu -rf
git clone https://github.com/mengning/menu.git
cd menu
mv test_exec.c test.c// 将test.c替换为test_exec.c,仍命名为test.c,为menu增加exec功能
make rootfs
2.gdb调试
设置三个断点:sys_execve,load_elf_binary,start_thread。
跟踪调试:
file linux-3.18.6/vmlinux
target remote:1234
3.查看elf文件具体内容信息
三、实验总结
了解了ELF文件的结构和组成部分,包括头部、段、节、符号表等,从而对程序的内部结构有更深入的认识。
理解ELF文件在编译、链接和执行过程中的作用和影响,包括程序加载、符号解析、动态链接等。掌握使用相关工具(如readelf、objdump、ld和gdb)分析和操作ELF文件的基本技巧,对调试和优化程序具有帮助。
加深对编译、链接和执行过程的理解,从而提高对程序开发和调试的能力。ELF文件是深入了解和学习程序编译、链接和执行的重要手段之一。通过实践和实验,可以更好地理解和应用ELF文件相关的知识,提高对程序的理解和掌握。