Subversion Repositories HelenOS

Rev

Rev 2726 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2726 vana 1
	-------------------------------------------------
2
	Building EFI Applications Using the GNU Toolchain
3
	-------------------------------------------------
4
 
5
		David Mosberger <davidm@hpl.hp.com>
6
 
7
			23 September 1999
8
 
9
 
10
		Copyright (c) 1999-2003 Hewlett-Packard Co.
11
 
12
Last update: 08/20/2003
13
 
14
* Introduction
15
 
16
This document has two parts: the first part describes how to develop
17
EFI applications for IA-64 and x86 using the GNU toolchain and the EFI
18
development environment contained in this directory.  The second part
19
describes some of the more subtle aspects of how this development
20
environment works.
21
 
22
 
23
 
24
* Part 1: Developing EFI Applications
25
 
26
 
27
** Prerequisites:
28
 
29
 To develop x86 EFI applications, the following tools are needed:
30
 
31
	- gcc-3.0 or newer (gcc 2.7.2 is NOT sufficient!)
32
	  As of gnu-efi-3.0b, the Redhat 8.0 toolchain is known to work,
33
	  but the Redhat 9.0 toolchain is not currently supported.
34
 
35
	- A version of "objcopy" that supports EFI applications.  To
36
	  check if your version includes EFI support, issue the
37
	  command:
38
 
39
		objcopy --help
40
 
41
	  and verify that the line "supported targets" contains the
42
	  string "efi-app-ia32".
43
 
44
	- For debugging purposes, it's useful to have a version of
45
	  "objdump" that supports EFI applications as well.  This
46
	  allows inspect and disassemble EFI binaries.
47
 
48
 To develop IA-64 EFI applications, the following tools are needed:
49
 
50
	- A version of gcc newer than July 30th 1999 (older versions
51
	  had problems with generating position independent code).
52
	  As of gnu-efi-3.0b, gcc-3.1 is known to work well.
53
 
54
	- A version of "objcopy" that supports EFI applications.  To
55
	  check if your version includes EFI support, issue the
56
	  command:
57
 
58
		objcopy --help
59
 
60
	  and verify that the line "supported targets" contains the
61
	  string "efi-app-ia64".
62
 
63
	- For debugging purposes, it's useful to have a version of
64
	  "objdump" that supports EFI applications as well.  This
65
	  allows inspect and disassemble EFI binaries.
66
 
67
 
68
** Directory Structure
69
 
70
This EFI development environment contains the following
71
subdirectories:
72
 
73
 inc:   This directory contains the EFI-related include files.  The
74
	files are taken from Intel's EFI source distribution, except
75
	that various fixes were applied to make it compile with the
76
	GNU toolchain.
77
 
78
 lib:   This directory contains the source code for Intel's EFI library.
79
	Again, the files are taken from Intel's EFI source
80
	distribution, with changes to make them compile with the GNU
81
	toolchain.
82
 
83
 gnuefi: This directory contains the glue necessary to convert ELF64
84
	binaries to EFI binaries.  Various runtime code bits, such as
85
	a self-relocator are included as well.  This code has been
86
	contributed by the Hewlett-Packard Company and is distributed
87
	under the GNU GPL.
88
 
89
 apps:	This directory contains a few simple EFI test apps.
90
 
91
** Setup
92
 
93
It is necessary to edit the Makefile in the directory containing this
94
README file before EFI applications can be built.  Specifically, you
95
should verify that macros CC, AS, LD, AR, RANLIB, and OBJCOPY point to
96
the appropriate compiler, assembler, linker, ar, and ranlib binaries,
97
respectively.
98
 
99
If you're working in a cross-development environment, be sure to set
100
macro ARCH to the desired target architecture ("ia32" for x86, "ia64"
101
for IA-64).  For convenience, this can also be done from the make
102
command line (e.g., "make ARCH=ia64").
103
 
104
 
105
** Building
106
 
107
To build the sample EFI applications provided in subdirectory "apps",
108
simply invoke "make" in the toplevel directory (the directory
109
containing this README file).  This should build lib/libefi.a and
110
gnuefi/libgnuefi.a first and then all the EFI applications such as a
111
apps/t6.efi.
112
 
113
 
114
** Running
115
 
116
Just copy the EFI application (e.g., apps/t6.efi) to the EFI
117
filesystem, boot EFI, and then select "Invoke EFI application" to run
118
the application you want to test.  Alternatively, you can invoke the
119
Intel-provided "nshell" application and then invoke your test binary
120
via the command line interface that "nshell" provides.
121
 
122
 
123
** Writing Your Own EFI Application
124
 
125
Suppose you have your own EFI application in a file called
126
"apps/myefiapp.c".  To get this application built by the GNU EFI build
127
environment, simply add "myefiapp.efi" to macro TARGETS in
128
apps/Makefile.  Once this is done, invoke "make" in the top level
129
directory.  This should result in EFI application apps/myefiapp.efi,
130
ready for execution.
131
 
132
The GNU EFI build environment allows to write EFI applications as
133
described in Intel's EFI documentation, except for two differences:
134
 
135
 - The EFI application's entry point is always called "efi_main".  The
136
   declaration of this routine is:
137
 
138
    EFI_STATUS efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
139
 
140
 - UNICODE string literals must be written as W2U(L"Sample String")
141
   instead of just L"Sample String".  The W2U() macro is defined in
142
   <efilib.h>.  This header file also declares the function W2UCpy()
143
   which allows to convert a wide string into a UNICODE string and
144
   store the result in a programmer-supplied buffer.
145
 
146
 
147
* Part 2: Inner Workings
148
 
149
WARNING: This part contains all the gory detail of how the GNU EFI
150
toolchain works.  Normal users do not have to worry about such
151
details.  Reading this part incurs a definite risk of inducing severe
152
headaches or other maladies.
153
 
154
The basic idea behind the GNU EFI build environment is to use the GNU
155
toolchain to build a normal ELF binary that, at the end, is converted
156
to an EFI binary.  EFI binaries are really just PE32+ binaries.  PE
157
stands for "Portable Executable" and is the object file format
158
Microsoft is using on its Windows platforms.  PE is basically the COFF
159
object file format with an MS-DOS2.0 compatible header slapped on in
160
front of it.  The "32" in PE32+ stands for 32 bits, meaning that PE32
161
is a 32-bit object file format.  The plus in "PE32+" indicates that
162
this format has been hacked to allow loading a 4GB binary anywhere in
163
a 64-bit address space (unlike ELF64, however, this is not a full
164
64-bit object file format because the entire binary cannot span more
165
than 4GB of address space).  EFI binaries are plain PE32+ binaries
166
except that the "subsystem id" differs from normal Windows binaries.
167
There are two flavors of EFI binaries: "applications" and "drivers"
168
and each has there own subsystem id and are identical otherwise.  At
169
present, the GNU EFI build environment supports the building of EFI
170
applications only, though it would be trivial to generate drivers, as
171
the only difference is the subsystem id.  For more details on PE32+,
172
see the spec at
173
 
174
	http://msdn.microsoft.com/library/specs/msdn_pecoff.htm.
175
 
176
In theory, converting a suitable ELF64 binary to PE32+ is easy and
177
could be accomplished with the "objcopy" utility by specifying option
178
--target=efi-app-ia32 (x86) or --target=efi-app-ia64 (IA-64).  But
179
life never is that easy, so here some complicating factors:
180
 
181
 (1) COFF sections are very different from ELF sections.
182
 
183
	ELF binaries distinguish between program headers and sections.
184
	The program headers describe the memory segments that need to
185
	be loaded/initialized, whereas the sections describe what
186
	constitutes those segments.  In COFF (and therefore PE32+) no
187
	such distinction is made.  Thus, COFF sections need to be page
188
	aligned and have a size that is a multiple of the page size
189
	(4KB for EFI), whereas ELF allows sections at arbitrary
190
	addresses and with arbitrary sizes.
191
 
192
 (2) EFI binaries should be relocatable.
193
 
194
	Since EFI binaries are executed in physical mode, EFI cannot
195
	guarantee that a given binary can be loaded at its preferred
196
	address.  EFI does _try_ to load a binary at it's preferred
197
	address, but if it can't do so, it will load it at another
198
	address and then relocate the binary using the contents of the
199
	.reloc section.
200
 
201
 (3) On IA-64, the EFI entry point needs to point to a function
202
     descriptor, not to the code address of the entry point.
203
 
204
 (4) The EFI specification assumes that wide characters use UNICODE
205
     encoding.
206
 
207
	ANSI C does not specify the size or encoding that a wide
208
	character uses.  These choices are "implementation defined".
209
	On most UNIX systems, the GNU toolchain uses a wchar_t that is
210
	4 bytes in size.  The encoding used for such characters is
211
	(mostly) UCS4.
212
 
213
In the following sections, we address how the GNU EFI build
214
environment addresses each of these issues.
215
 
216
 
217
** (1) Accommodating COFF Sections
218
 
219
In order to satisfy the COFF constraint of page-sized and page-aligned
220
sections, the GNU EFI build environment uses the special linker script
221
in gnuefi/elf_$(ARCH)_efi.lds where $(ARCH) is the target architecture
222
("ia32" for x86, and "ia64" for IA-64).  This script is set up to
223
create only eight COFF section, each page aligned and page sized.
224
These eight sections are used to group together the much greater
225
number of sections that are typically present in ELF object files.
226
Specifically:
227
 
228
 .hash
229
	Collects the ELF .hash info (this section _must_ be the first
230
	section in order to build a shared object file; the section is
231
	not actually loaded or used at runtime).
232
 
233
 .text
234
	Collects all sections containing executable code.
235
 
236
 .data
237
	Collects read-only and read-write data, literal string data,
238
	global offset tables, the uninitialized data segment (bss) and
239
	various other sections containing data.
240
 
241
	The reason read-only data is placed here instead of the in
242
	.text is to make it possible to disassemble the .text section
243
	without getting garbage due to read-only data.  Besides, since
244
	EFI binaries execute in physical mode, differences in page
245
	protection do not matter.
246
 
247
	The reason the uninitialized data is placed in this section is
248
	that the EFI loader appears to be unable to handle sections
249
	that are allocated but not loaded from the binary.
250
 
251
 .dynamic, .dynsym, .rela, .rel, .reloc
252
	These sections contains the dynamic information necessary to
253
	self-relocate the binary (see below).
254
 
255
A couple of more points worth noting about the linker script:
256
 
257
 o On IA-64, the global pointer symbol (__gp) needs to be placed such
258
   that the _entire_ EFI binary can be addressed using the signed
259
   22-bit offset that the "addl" instruction affords.  Specifically,
260
   this means that __gp should be placed at ImageBase + 0x200000.
261
   Strictly speaking, only a couple of symbols need to be addressable
262
   in this fashion, so with some care it should be possible to build
263
   binaries much larger than 4MB.  To get a list of symbols that need
264
   to be addressable in this fashion, grep the assembly files in
265
   directory gnuefi for the string "@gprel".
266
 
267
 o The link address (ImageBase) of the binary is (arbitrarily) set to
268
   zero.  This could be set to something larger to increase the chance
269
   of EFI being able to load the binary without requiring relocation.
270
   However, a start address of 0 makes debugging a wee bit easier
271
   (great for those of us who can add, but not subtract... ;-).
272
 
273
 o The relocation related sections (.dynamic, .rel, .rela, .reloc)
274
   cannot be placed inside .data because some tools in the GNU
275
   toolchain rely on the existence of these sections.
276
 
277
 o Some sections in the ELF binary intentionally get dropped when
278
   building the EFI binary.  Particularly noteworthy are the dynamic
279
   relocation sections for the .plabel and .reloc sections.  It would
280
   be _wrong_ to include these sections in the EFI binary because it
281
   would result in .reloc and .plabel being relocated twice (once by
282
   the EFI loader and once by the self-relocator; see below for a
283
   description of the latter).  Specifically, only the sections
284
   mentioned with the -j option in the final "objcopy" command are
285
   retained in the EFI binary (see apps/Makefile).
286
 
287
 
288
** (2) Building Relocatable Binaries
289
 
290
ELF binaries are normally linked for a fixed load address and are thus
291
not relocatable.  The only kind of ELF object that is relocatable are
292
shared objects ("shared libraries").  However, even those objects are
293
usually not completely position independent and therefore require
294
runtime relocation by the dynamic loader.  For example, IA-64 binaries
295
normally require relocation of the global offset table.
296
 
297
The approach to building relocatable binaries in the GNU EFI build
298
environment is to:
299
 
300
 (a) build an ELF shared object
301
 
302
 (b) link it together with a self-relocator that takes care of
303
     applying the dynamic relocations that may be present in the
304
     ELF shared object
305
 
306
 (c) convert the resulting image to an EFI binary
307
 
308
The self-relocator is of course architecture dependent.  The x86
309
version can be found in gnuefi/reloc_ia32.c, the IA-64 version can be
310
found in gnuefi/reloc_ia64.S.
311
 
312
The self-relocator operates as follows: the startup code invokes it
313
right after EFI has handed off control to the EFI binary at symbol
314
"_start".  Upon activation, the self-relocator searches the .dynamic
315
section (whose starting address is given by symbol _DYNAMIC) for the
316
dynamic relocation information, which can be found in the DT_REL,
317
DT_RELSZ, and DT_RELENT entries of the dynamic table (DT_RELA,
318
DT_RELASZ, and DT_RELAENT in the case of rela relocations, as is the
319
case for IA-64).  The dynamic relocation information points to the ELF
320
relocation table.  Once this table is found, the self-relocator walks
321
through it, applying each relocation one by one.  Since the EFI
322
binaries are fully resolved shared objects, only a subset of all
323
possible relocations need to be supported.  Specifically, on x86 only
324
the R_386_RELATIVE relocation is needed.  On IA-64, the relocations
325
R_IA64_DIR64LSB, R_IA64_REL64LSB, and R_IA64_FPTR64LSB are needed.
326
Note that the R_IA64_FPTR64LSB relocation requires access to the
327
dynamic symbol table.  This is why the .dynsym section is included in
328
the EFI binary.  Another complication is that this relocation requires
329
memory to hold the function descriptors (aka "procedure labels" or
330
"plabels").  Each function descriptor uses 16 bytes of memory.  The
331
IA-64 self-relocator currently reserves a static memory area that can
332
hold 100 of these descriptors.  If the self-relocator runs out of
333
space, it causes the EFI binary to fail with error code 5
334
(EFI_BUFFER_TOO_SMALL).  When this happens, the manifest constant
335
MAX_FUNCTION_DESCRIPTORS in gnuefi/reloc_ia64.S should be increased
336
and the application recompiled.  An easy way to count the number of
337
function descriptors required by an EFI application is to run the
338
command:
339
 
340
  objdump --dynamic-reloc example.so | fgrep FPTR64 | wc -l
341
 
342
assuming "example" is the name of the desired EFI application.
343
 
344
 
345
** (3) Creating the Function Descriptor for the IA-64 EFI Binaries
346
 
347
As mentioned above, the IA-64 PE32+ format assumes that the entry
348
point of the binary is a function descriptor.  A function descriptors
349
consists of two double words: the first one is the code entry point
350
and the second is the global pointer that should be loaded before
351
calling the entry point.  Since the ELF toolchain doesn't know how to
352
generate a function descriptor for the entry point, the startup code
353
in gnuefi/crt0-efi-ia64.S crafts one manually by with the code:
354
 
355
	        .section .plabel, "a"
356
	_start_plabel:
357
	        data8   _start
358
	        data8   __gp
359
 
360
this places the procedure label for entry point _start in a section
361
called ".plabel".  Now, the only problem is that _start and __gp need
362
to be relocated _before_ EFI hands control over to the EFI binary.
363
Fortunately, PE32+ defines a section called ".reloc" that can achieve
364
this.  Thus, in addition to manually crafting the function descriptor,
365
the startup code also crafts a ".reloc" section that has will cause
366
the EFI loader to relocate the function descriptor before handing over
367
control to the EFI binary (again, see the PECOFF spec mentioned above
368
for details).
369
 
370
A final question may be why .plabel and .reloc need to go in their own
371
COFF sections.  The answer is simply: we need to be able to discard
372
the relocation entries that are generated for these sections.  By
373
placing them in these sections, the relocations end up in sections
374
".rela.plabel" and ".rela.reloc" which makes it easy to filter them
375
out in the filter script.  Also, the ".reloc" section needs to be in
376
its own section so that the objcopy program can recognize it and can
377
create the correct directory entries in the PE32+ binary.
378
 
379
 
380
** (4) Convenient and Portable Generation of UNICODE String Literals
381
 
382
As of gnu-efi-3.0, we make use (and somewhat abuse) the gcc option
383
that forces wide characters (WCHAR_T) to use short integers (2 bytes) 
384
instead of integers (4 bytes). This way we match the Unicode character
385
size. By abuse, we mean that we rely on the fact that the regular ASCII
386
characters are encoded the same way between (short) wide characters 
387
and Unicode and basically only use the first byte. This allows us
388
to just use them interchangeably.
389
 
390
The gcc option to force short wide characters is : -fshort-wchar
391
 
392
			* * * The End * * *