作者:陈曦
日期:2012-6-23 14:24:27
环境:[Mac 10.7.1 Lion Intel i3 支持64位指令 gcc4.2.1 xcode4.2]
转载请注明出处
Q1: 编译生成的可执行文件内部是如何被执行的?
A: 当然,首先需要知道它的结构。先编写一个简单的程序,保存为testForC.c:
#include <stdio.h>
#include <string.h>
#define PRINT_D(longValue) printf(#longValue" is %ld\n", ((long)longValue));
#define PRINT_STR(str) printf(#str" is %s\n", (str));
int main()
{
printf("hello\n");
return 0;
}
编译生成32位应用程序testForC.使用file命令得到它的信息:
Q2: Mach-O是什么?
A: 它表示mach架构下的目标文件。我们可以通过工具MachOView来查看:
由上图可以看到mach-o格式开头的基本信息,包括开头的魔数、对应CPU类型等信息。
Q3: 这些结构在哪里可以看到?
A: 在mach-o/arch.h头文件可以看到如下结构:
typedef struct {
const char *name;
cpu_type_t cputype;
cpu_subtype_t cpusubtype;
enum NXByteOrder byteorder;
const char *description;
} NXArchInfo;
它包含一些架构信息,在mach-o/loader.h头文件中包含mach-o格式文件头的格式:
/*
* The 32-bit mach header appears at the very beginning of the object file for
* 32-bit architectures.
*/
struct mach_header {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
};
/* Constant for the magic field of the mach_header (32-bit architectures) */
#define MH_MAGIC 0xfeedface /* the mach magic number */
#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
Q4: 上面的cputype是CPU_TYPE_I386表示的是32位吧,有的应用程序包含32位和64位体系的代码,结构是如何的?
A: 先生成一个这样的文件。依然使用文章开头的代码,使用如下命令编译:
gcc -o testForC testForC.c -arch i386 -arch x86_64
继续使用file命令得到它的信息:
可以看出,它包含两种体系代码。我们同样使用MachOView工具查看它的内部信息:
可以看出,它内部包含了两种架构的信息,并且它的开头有一些特定的信息,之后才是不同架构的信息。
Q5: 上图中的Load Commands表示什么?
A: 它记录了文件中各个段(如代码段,数据段等)如何映射到内存,也包含了文件使用的动态链接器以及文件需要的动态库,同时也包含文件和动态链接器使用的符号表。Load Commands对应的结构定义如下:
/*
* The segment load command indicates that a part of this file is to be
* mapped into the task's address space. The size of this segment in memory,
* vmsize, maybe equal to or larger than the amount to map from this file,
* filesize. The file is mapped starting at fileoff to the beginning of
* the segment in memory, vmaddr. The rest of the memory of the segment,
* if any, is allocated zero fill on demand. The segment's maximum virtual
* memory protection and initial virtual memory protection are specified
* by the maxprot and initprot fields. If the segment has sections then the
* section structures directly follow the segment command and their size is
* reflected in cmdsize.
*/
struct segment_command { /* for 32-bit architectures */
uint32_t cmd; /* LC_SEGMENT */
uint32_t cmdsize; /* includes sizeof section structs */
char segname[16]; /* segment name */
uint32_t vmaddr; /* memory address of this segment */
uint32_t vmsize; /* memory size of this segment */
uint32_t fileoff; /* file offset of this segment */
uint32_t filesize; /* amount to map from the file */
vm_prot_t maxprot; /* maximum VM protection */
vm_prot_t initprot; /* initial VM protection */
uint32_t nsects; /* number of sections in segment */
uint32_t flags; /* flags */
};
比如说,对于testForC的第一个截图:
_TEXT段的VM Address为0x1000.
对于section __text, 它对应的地址是:
由此,我们可以得到__text在文件中的真实位置为: 0x1F10 - 0x1000 = 0xF10.
作者:陈曦
日期:2012-6-23 14:24:27
环境:[Mac 10.7.1 Lion Intel i3 支持64位指令 gcc4.2.1 xcode4.2]
转载请注明出处