1 #ifndef _A_OUT_H
2 #define _A_OUT_H
3
4 #define __GNU_EXEC_MACROS__
5
// 第6--108行是该文件第1部分。定义目标文件执行结构以及相关操作的宏定义。
// 目标文件头结构。参见程序后的详细说明。
// =============================
// unsigned long a_magic // 执行文件魔数。使用N_MAGIC等宏访问。
// unsigned a_text // 代码长度,字节数。
// unsigned a_data // 数据长度,字节数。
// unsigned a_bss // 文件中的未初始化数据区长度,字节数。
// unsigned a_syms // 文件中的符号表长度,字节数。
// unsigned a_entry // 执行开始地址。
// unsigned a_trsize // 代码重定位信息长度,字节数。
// unsigned a_drsize // 数据重定位信息长度,字节数。
// -----------------------------
6 struct exec {
7 unsigned long a_magic; /* Use macros N_MAGIC, etc for access */
8 unsigned a_text; /* length of text, in bytes */
9 unsigned a_data; /* length of data, in bytes */
10 unsigned a_bss; /* length of uninitialized data area for file, in bytes */
11 unsigned a_syms; /* length of symbol table data in file, in bytes */
12 unsigned a_entry; /* start address */
13 unsigned a_trsize; /* length of relocation info for text, in bytes */
14 unsigned a_drsize; /* length of relocation info for data, in bytes */
15 };
16
// 用于取上述exec结构中的魔数。
17 #ifndef N_MAGIC
18 #define N_MAGIC(exec) ((exec).a_magic)
19 #endif
20
21 #ifndef OMAGIC
22 /* Code indicating object file or impure executable. */
/* 指明为目标文件或者不纯的可执行文件的代号 */
// 历史上最早在PDP-11计算机上,魔数(幻数)是八进制数0407(0x107)。它位于执行程序
// 头结构的开始处。原本是PDP-11的一条跳转指令,表示跳转到随后7个字后的代码开始处。
// 这样加载程序(loader)就可以在把执行文件放入内存后直接跳转到指令开始处运行。 现在
// 已没有程序使用这种方法,但这个八进制数却作为识别文件类型的标志(魔数)保留了下来。
// OMAGIC可以认为是Old Magic 的意思。
23 #define OMAGIC 0407
24 /* Code indicating pure executable. */
/* 指明为纯可执行文件的代号 */ // New Magic,1975年以后开始使用。涉及虚存机制。
25 #define NMAGIC 0410 // 0410 == 0x108
26 /* Code indicating demand-paged executable. */
/* 指明为需求分页处理的可执行文件 */ // 其头结构占用文件开始处1K空间。
27 #define ZMAGIC 0413 // 0413 == 0x10b
28 #endif /* not OMAGIC */
29 // 另外还有一个QMAGIC,是为了节约磁盘容量,把盘上执行文件的头结构与代码紧凑存放。
// 下面宏用于判断魔数字段的正确性。如果魔数不能被识别,则返回真。
30 #ifndef N_BADMAG
31 #define N_BADMAG(x) \
32 (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
33 && N_MAGIC(x) != ZMAGIC)
34 #endif
35
36 #define _N_BADMAG(x) \
37 (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
38 && N_MAGIC(x) != ZMAGIC)
39
// 目标文件头结构末端到1024字节之间的长度。
40 #define _N_HDROFF(x) (SEGMENT_SIZE - sizeof (struct exec))
41
// 下面宏用于操作目标文件的内容,包括.o模块文件和可执行文件。
// 代码部分起始偏移值。
// 如果文件是 ZMAGIC类型的,即是执行文件,那么代码部分是从执行文件的1024字节偏移处
// 开始;否则执行代码部分紧随执行头结构末端(32字节)开始,即文件是模块文件(OMAGIC
// 类型)。
42 #ifndef N_TXTOFF
43 #define N_TXTOFF(x) \
44 (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec))
45 #endif
46
// 数据部分起始偏移值。从代码部分末端开始。
47 #ifndef N_DATOFF
48 #define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
49 #endif
50
// 代码重定位信息偏移值。从数据部分末端开始。
51 #ifndef N_TRELOFF
52 #define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
53 #endif
54
// 数据重定位信息偏移值。从代码重定位信息末端开始。
55 #ifndef N_DRELOFF
56 #define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize)
57 #endif
58
// 符号表偏移值。从上面数据段重定位表末端开始。
59 #ifndef N_SYMOFF
60 #define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize)
61 #endif
62
// 字符串信息偏移值。在符号表之后。
63 #ifndef N_STROFF
64 #define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms)
65 #endif
66
// 下面对可执行文件被加载到内存(逻辑空间)中的位置情况进行操作。
67 /* Address of text segment in memory after it is loaded. */
/* 代码段加载后在内存中的地址 */
68 #ifndef N_TXTADDR
69 #define N_TXTADDR(x) 0 // 可见,代码段从地址0开始执行。
70 #endif
71
72 /* Address of data segment in memory after it is loaded.
73 Note that it is up to you to define SEGMENT_SIZE
74 on machines not listed here. */
/* 数据段加载后在内存中的地址。
注意,对于下面没有列出名称的机器,需要你自己来定义
对应的SEGMENT_SIZE */
75 #if defined(vax) || defined(hp300) || defined(pyr)
76 #define SEGMENT_SIZE PAGE_SIZE
77 #endif
78 #ifdef hp300
79 #define PAGE_SIZE 4096
80 #endif
81 #ifdef sony
82 #define SEGMENT_SIZE 0x2000
83 #endif /* Sony. */
84 #ifdef is68k
85 #define SEGMENT_SIZE 0x20000
86 #endif
87 #if defined(m68k) && defined(PORTAR)
88 #define PAGE_SIZE 0x400
89 #define SEGMENT_SIZE PAGE_SIZE
90 #endif
91
// 这里,Linux 0.12内核把内存页定义为4KB,段大小定义为1KB。因此没有使用上面的定义。
92 #define PAGE_SIZE 4096
93 #define SEGMENT_SIZE 1024
94
// 以段为界的大小(进位方式)。
95 #define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
96
// 代码段尾地址。
97 #define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
98
// 数据段开始地址。
// 如果文件是OMAGIC类型的,那么数据段就直接紧随代码段后面。否则的话数据段地址从代码
// 段后面段边界开始(1KB边界对齐)。例如ZMAGIC类型的文件。
99 #ifndef N_DATADDR
100 #define N_DATADDR(x) \
101 (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
102 : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
103 #endif
104
105 /* Address of bss segment in memory after it is loaded. */
/* bss段加载到内存以后的地址 */
// 未初始化数据段bbs位于数据段后面,紧跟数据段。
106 #ifndef N_BSSADDR
107 #define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
108 #endif
109
// 第110—185行是第2部分。对目标文件中的符号表项和相关操作宏进行定义和说明。
// a.out目标文件中符号表项结构(符号表记录结构)。参见程序后的详细说明。
110 #ifndef N_NLIST_DECLARED
111 struct nlist {
112 union {
113 char *n_name;
114 struct nlist *n_next;
115 long n_strx;
116 } n_un;
117 unsigned char n_type; // 该字节分成3个字段,146--154行是相应字段的屏蔽码。
118 char n_other;
119 short n_desc;
120 unsigned long n_value;
121 };
122 #endif
123
// 下面定义nlist结构中n_type字段值的常量符号。
124 #ifndef N_UNDF
125 #define N_UNDF 0
126 #endif
127 #ifndef N_ABS
128 #define N_ABS 2
129 #endif
130 #ifndef N_TEXT
131 #define N_TEXT 4
132 #endif
133 #ifndef N_DATA
134 #define N_DATA 6
135 #endif
136 #ifndef N_BSS
137 #define N_BSS 8
138 #endif
139 #ifndef N_COMM
140 #define N_COMM 18
141 #endif
142 #ifndef N_FN
143 #define N_FN 15
144 #endif
145
// 以下3个常量定义是nlist结构中n_type字段的屏蔽码(八进程表示)。
146 #ifndef N_EXT
147 #define N_EXT 1 // 0x01(0b0000,0001)符号是否是外部的(全局的)。
148 #endif
149 #ifndef N_TYPE
150 #define N_TYPE 036 // 0x1e(0b0001,1110)符号的类型位。
151 #endif
152 #ifndef N_STAB // STAB -- 符号表类型(Symbol table types)。
153 #define N_STAB 0340 // 0xe0(0b1110,0000)这几个比特用于符号调试器。
154 #endif
155
156 /* The following type indicates the definition of a symbol as being
157 an indirect reference to another symbol. The other symbol
158 appears as an undefined reference, immediately following this symbol.
159
160 Indirection is asymmetrical. The other symbol's value will be used
161 to satisfy requests for the indirect symbol, but not vice versa.
162 If the other symbol does not have a definition, libraries will
163 be searched to find a definition. */
/* 下面的类型指明对一个符号的定义是作为对另一个符号的间接引用。紧接该
* 符号的其他的符号呈现为未定义的引用。
*
* 这种间接引用是不对称的。另一个符号的值将被用于满足间接符号的要求,
* 但反之则不然。如果另一个符号没有定义,则将搜索库来寻找一个定义 */
164 #define N_INDR 0xa
165
166 /* The following symbols refer to set elements.
167 All the N_SET[ATDB] symbols with the same name form one set.
168 Space is allocated for the set in the text section, and each set
169 element's value is stored into one word of the space.
170 The first word of the space is the length of the set (number of elements).
171
172 The address of the set is made into an N_SETV symbol
173 whose name is the same as the name of the set.
174 This symbol acts like a N_DATA global symbol
175 in that it can satisfy undefined external references. */
/* 下面的符号与集合元素有关。所有具有相同名称N_SET[ATDB]的符号
形成一个集合。在代码部分中已为集合分配了空间,并且每个集合元素
的值存放在一个字(word)的空间中。空间的第一个字存有集合的长度(集合元素数目)。
集合的地址被放入一个N_SETV符号中,它的名称与集合同名。
在满足未定义的外部引用方面,该符号的行为象一个N_DATA全局符号。*/
176
177 /* These appear as input to LD, in a .o file. */
/* 以下这些符号在 .o 文件中是作为链接程序LD的输入。*/
178 #define N_SETA 0x14 /* Absolute set element symbol */ /* 绝对集合元素符号 */
179 #define N_SETT 0x16 /* Text set element symbol */ /* 代码集合元素符号 */
180 #define N_SETD 0x18 /* Data set element symbol */ /* 数据集合元素符号 */
181 #define N_SETB 0x1A /* Bss set element symbol */ /* Bss集合元素符号 */
182
183 /* This is output from LD. */
/* 下面是LD的输出。*/
184 #define N_SETV 0x1C /* Pointer to set vector in data area. */
/* 指向数据区中集合向量。*/
185
186 #ifndef N_RELOCATION_INFO_DECLARED
187
188 /* This structure describes a single relocation to be performed.
189 The text-relocation section of the file is a vector of these structures,
190 all of which apply to the text section.
191 Likewise, the data-relocation section applies to the data section. */
/* 下面结构描述单个重定位操作的执行。
文件的代码重定位部分是这些结构的一个数组,所有这些适用于代码部分。
类似地,数据重定位部分用于数据部分。*/
192
// a.out目标文件中代码和数据重定位信息结构。
193 struct relocation_info
194 {
195 /* Address (within segment) to be relocated. */
/* 段内需要重定位的地址。*/
196 int r_address;
197 /* The meaning of r_symbolnum depends on r_extern. */
/* r_symbolnum的含义与r_extern有关。*/
198 unsigned int r_symbolnum:24;
199 /* Nonzero means value is a pc-relative offset
200 and it should be relocated for changes in its own address
201 as well as for changes in the symbol or section specified. */
/* 非零意味着值是一个pc相关的偏移值,因而在其自己地址空间
以及符号或指定的节改变时,需要被重定位 */
202 unsigned int r_pcrel:1;
203 /* Length (as exponent of 2) of the field to be relocated.
204 Thus, a value of 2 indicates 1<<2 bytes. */
/* 需要被重定位的字段长度(是2的次方)。
因此,若值是2则表示1<<2字节数。*/
205 unsigned int r_length:2;
206 /* 1 => relocate with value of symbol.
207 r_symbolnum is the index of the symbol
208 in file's the symbol table.
209 0 => relocate with the address of a segment.
210 r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
211 (the N_EXT bit may be set also, but signifies nothing). */
/* 1 => 以符号的值重定位。
r_symbolnum是文件符号表中符号的索引。
0 => 以段的地址进行重定位。
r_symbolnum是N_TEXT、N_DATA、N_BSS或N_ABS
(N_EXT比特位也可以被设置,但是毫无意义)。*/
212 unsigned int r_extern:1;
213 /* Four bits that aren't used, but when writing an object file
214 it is desirable to clear them. */
/* 没有使用的4个比特位,但是当进行写一个目标文件时
最好将它们复位掉。*/
215 unsigned int r_pad:4;
216 };
217 #endif /* no N_RELOCATION_INFO_DECLARED. */
218
219
220 #endif /* __A_OUT_GNU_H__ */
221