关于 elf 文件、部分 headers 以及当我们 运行 一个应用程序时它们通常如何工作的一些初学者问题
Some beginner questions about elf files, sections headers and how they work in general when we run an application
我正在了解 elf 文件。我读了一些关于它的东西,我开始对它了解得很少,但有些事情让我感到困惑。我想继续学习并掌握它,但首先我想确保我把最简单的事情做对了。我会在下面说出我所知道的,如果我犯了错误,请纠正我。
当您编写 C 应用程序并对其进行编译(例如使用 gcc)时,它会被翻译成表示代码和数据的机器指令。
调用编译器的输出是一个 elf 文件。
elf 文件包含(除其他事项外)一个 header 部分,它基本上是一系列 Elf64_Shdr,每个部分代表您编译的应用程序包含的每个部分。
所以基本上一个部分只是一些代表代码或数据的机器指令和一些关于它的信息,比如它在哪里(第一条指令的地址)和它有多长(大小),它是可写的还是可读的(一些标志)等我对节和节header的理解是否正确?
当我们 运行 make 命令并将 elf 文件传递给它时,链接器开始工作并查看编译器创建的所有部分,查看它们的名称和属性并将它们分组到 'segments'遵循 ld 脚本文件的规则并创建我们可以执行的可执行文件 运行 所以基本上段只不过是具有相同属性的部分,它们组合在一个具有特定名称的公共部分中。 这是正确的吗?
然后当我们实际 运行 创建的可执行文件时,加载器开始运行并查看链接器创建的这些段,并通过读取它们包含的信息将机器指令映射到各种内存位置,因此进程可以 运行。这就是所谓的(在我的理解中)记忆图像。 这是正确的吗?
感谢您的阅读,帮我解开疑惑,谢谢。
您的描述中存在多处不准确之处,不清楚是您对所涉及的处理的理解不准确,还是描述它们。
When you write a C application and you compile it(say with gcc) it gets translated into machine instructions which represent code and data.
这并不完全准确:"machine instructions" 和 "machine code" 之间存在差异。
当你编译一个 .c
文件时,一些编译器会将它翻译成机器指令(汇编),然后将它传递给汇编程序以生成机器代码(GCC 就是这样做的)。其他编译器集成了汇编器,有效地跳过了汇编生成步骤(Clang 就是这样做的)。
The output of invoking the compiler is an elf file.
在一些但不是所有系统上,编译的结果是一个可重定位的ELF文件。其他系统生成不同格式的目标文件,例如 XCOFF 或 Mach-O。
The elf file contains(among other things) a section header which is basically a series of Elf64_Shdr each for every section your compiled application contains.
应用程序尚未构建,所以这是不准确的。此外,Elf64_Shdr
仅适用于 64 位 ELF 平台;在 32 位机器上是 Elf32_Ehdr
.
When we run the make command
make
命令没有任何作用。它只是根据需要调用编译器和 linker(或其他工具)。您可以将其替换为 shell 脚本,或仅手动键入命令。
and pass it the elf file
link步骤涉及一个或多个(通常更多)可重定位ELF
目标文件、归档库和动态库。
the linker comes into play and looks at all sections created by the compiler, at their names and attributes and groups them into 'segments' following the rules of a ld script file
要了解 link 人的工作,您可以阅读此 series of blog posts。
您的描述轻视了 link 人所做的事情。 linker 更复杂,执行您没有提到的重定位解析,以及许多其他任务。
and creates the executable file which we can run.
通常是正确的。
您可以要求 link 人员将几个可重定位的目标文件组合成一个 组合的 目标文件(带有 ld -r foo.o bar.o -o combined.o
),在这种情况下,结果不会是一个可执行文件。
您还可以要求 link 人员 link 一个共享库而不是 link 一个可执行文件。
So basically segments are nothing more than sections of same attributes grouped togheter in a common section with a specific name.
错误。 很多 link 比将部分分组在一起。
Then when we actually run the created executable the loader comes into play
加载器只对动态link编辑的可执行文件起作用。全静态可执行文件没有加载器,直接由内核本身启动。
and looks at these segments created by the linker and by reading this information which they contain it maps the machine instructions to various memory locations so the process can run. This is what is called(in my understanding) a memory image.
大部分正确。内存映像的某些部分根本不是来自磁盘(例如线程本地存储和组合 .bss
部分的内容)
我正在了解 elf 文件。我读了一些关于它的东西,我开始对它了解得很少,但有些事情让我感到困惑。我想继续学习并掌握它,但首先我想确保我把最简单的事情做对了。我会在下面说出我所知道的,如果我犯了错误,请纠正我。
当您编写 C 应用程序并对其进行编译(例如使用 gcc)时,它会被翻译成表示代码和数据的机器指令。 调用编译器的输出是一个 elf 文件。 elf 文件包含(除其他事项外)一个 header 部分,它基本上是一系列 Elf64_Shdr,每个部分代表您编译的应用程序包含的每个部分。 所以基本上一个部分只是一些代表代码或数据的机器指令和一些关于它的信息,比如它在哪里(第一条指令的地址)和它有多长(大小),它是可写的还是可读的(一些标志)等我对节和节header的理解是否正确?
当我们 运行 make 命令并将 elf 文件传递给它时,链接器开始工作并查看编译器创建的所有部分,查看它们的名称和属性并将它们分组到 'segments'遵循 ld 脚本文件的规则并创建我们可以执行的可执行文件 运行 所以基本上段只不过是具有相同属性的部分,它们组合在一个具有特定名称的公共部分中。 这是正确的吗?
然后当我们实际 运行 创建的可执行文件时,加载器开始运行并查看链接器创建的这些段,并通过读取它们包含的信息将机器指令映射到各种内存位置,因此进程可以 运行。这就是所谓的(在我的理解中)记忆图像。 这是正确的吗?
感谢您的阅读,帮我解开疑惑,谢谢。
您的描述中存在多处不准确之处,不清楚是您对所涉及的处理的理解不准确,还是描述它们。
When you write a C application and you compile it(say with gcc) it gets translated into machine instructions which represent code and data.
这并不完全准确:"machine instructions" 和 "machine code" 之间存在差异。
当你编译一个 .c
文件时,一些编译器会将它翻译成机器指令(汇编),然后将它传递给汇编程序以生成机器代码(GCC 就是这样做的)。其他编译器集成了汇编器,有效地跳过了汇编生成步骤(Clang 就是这样做的)。
The output of invoking the compiler is an elf file.
在一些但不是所有系统上,编译的结果是一个可重定位的ELF文件。其他系统生成不同格式的目标文件,例如 XCOFF 或 Mach-O。
The elf file contains(among other things) a section header which is basically a series of Elf64_Shdr each for every section your compiled application contains.
应用程序尚未构建,所以这是不准确的。此外,Elf64_Shdr
仅适用于 64 位 ELF 平台;在 32 位机器上是 Elf32_Ehdr
.
When we run the make command
make
命令没有任何作用。它只是根据需要调用编译器和 linker(或其他工具)。您可以将其替换为 shell 脚本,或仅手动键入命令。
and pass it the elf file
link步骤涉及一个或多个(通常更多)可重定位ELF
目标文件、归档库和动态库。
the linker comes into play and looks at all sections created by the compiler, at their names and attributes and groups them into 'segments' following the rules of a ld script file
要了解 link 人的工作,您可以阅读此 series of blog posts。
您的描述轻视了 link 人所做的事情。 linker 更复杂,执行您没有提到的重定位解析,以及许多其他任务。
and creates the executable file which we can run.
通常是正确的。
您可以要求 link 人员将几个可重定位的目标文件组合成一个 组合的 目标文件(带有 ld -r foo.o bar.o -o combined.o
),在这种情况下,结果不会是一个可执行文件。
您还可以要求 link 人员 link 一个共享库而不是 link 一个可执行文件。
So basically segments are nothing more than sections of same attributes grouped togheter in a common section with a specific name.
错误。 很多 link 比将部分分组在一起。
Then when we actually run the created executable the loader comes into play
加载器只对动态link编辑的可执行文件起作用。全静态可执行文件没有加载器,直接由内核本身启动。
and looks at these segments created by the linker and by reading this information which they contain it maps the machine instructions to various memory locations so the process can run. This is what is called(in my understanding) a memory image.
大部分正确。内存映像的某些部分根本不是来自磁盘(例如线程本地存储和组合 .bss
部分的内容)