| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 | 	-------------------------------------------------	Building EFI Applications Using the GNU Toolchain	-------------------------------------------------		David Mosberger <davidm@hpl.hp.com>			23 September 1999		Copyright (c) 1999-2007 Hewlett-Packard Co.		Copyright (c) 2006-2010 Intel Co.Last update: 04/09/2007* IntroductionThis document has two parts: the first part describes how to developEFI applications for IA-64,x86 and x86_64 using the GNU toolchain and the EFIdevelopment environment contained in this directory.  The second partdescribes some of the more subtle aspects of how this developmentenvironment works.* Part 1: Developing EFI Applications** Prerequisites: To develop x86 and x86_64 EFI applications, the following tools are needed:	- gcc-3.0 or newer (gcc 2.7.2 is NOT sufficient!)	  As of gnu-efi-3.0b, the Redhat 8.0 toolchain is known to work,	  but the Redhat 9.0 toolchain is not currently supported.	- A version of "objcopy" that supports EFI applications.  To	  check if your version includes EFI support, issue the	  command:		objcopy --help	  Verify that the line "supported targets" contains the string	  "efi-app-ia32" and "efi-app-x86_64" and that the "-j" option	  accepts wildcards. The binutils release binutils-2.24	  supports Intel64 EFI and accepts wildcard section names.	- For debugging purposes, it's useful to have a version of	  "objdump" that supports EFI applications as well.  This	  allows inspect and disassemble EFI binaries. To develop IA-64 EFI applications, the following tools are needed:	- A version of gcc newer than July 30th 1999 (older versions	  had problems with generating position independent code).	  As of gnu-efi-3.0b, gcc-3.1 is known to work well.	- A version of "objcopy" that supports EFI applications.  To	  check if your version includes EFI support, issue the	  command:		objcopy --help	  Verify that the line "supported targets" contains the string	  "efi-app-ia64" and that the "-j" option accepts wildcards.	- For debugging purposes, it's useful to have a version of	  "objdump" that supports EFI applications as well.  This	  allows inspect and disassemble EFI binaries.** Directory StructureThis EFI development environment contains the followingsubdirectories: inc:   This directory contains the EFI-related include files.  The	files are taken from Intel's EFI source distribution, except	that various fixes were applied to make it compile with the	GNU toolchain. lib:   This directory contains the source code for Intel's EFI library.	Again, the files are taken from Intel's EFI source	distribution, with changes to make them compile with the GNU	toolchain. gnuefi: This directory contains the glue necessary to convert ELF64	binaries to EFI binaries.  Various runtime code bits, such as	a self-relocator are included as well.  This code has been	contributed by the Hewlett-Packard Company and is distributed	under the GNU GPL. apps:	This directory contains a few simple EFI test apps.** SetupIt is necessary to edit the Makefile in the directory containing thisREADME file before EFI applications can be built.  Specifically, youshould verify that macros CC, AS, LD, AR, RANLIB, and OBJCOPY point tothe appropriate compiler, assembler, linker, ar, and ranlib binaries,respectively.If you're working in a cross-development environment, be sure to setmacro ARCH to the desired target architecture ("ia32" for x86, "x86_64" forx86_64 and "ia64" for IA-64).  For convenience, this can also be done fromthe make command line (e.g., "make ARCH=ia64").** BuildingTo build the sample EFI applications provided in subdirectory "apps",simply invoke "make" in the toplevel directory (the directorycontaining this README file).  This should build lib/libefi.a andgnuefi/libgnuefi.a first and then all the EFI applications such as aapps/t6.efi.** RunningJust copy the EFI application (e.g., apps/t6.efi) to the EFIfilesystem, boot EFI, and then select "Invoke EFI application" to runthe application you want to test.  Alternatively, you can invoke theIntel-provided "nshell" application and then invoke your test binaryvia the command line interface that "nshell" provides.** Writing Your Own EFI ApplicationSuppose you have your own EFI application in a file called"apps/myefiapp.c".  To get this application built by the GNU EFI buildenvironment, simply add "myefiapp.efi" to macro TARGETS inapps/Makefile.  Once this is done, invoke "make" in the top leveldirectory.  This should result in EFI application apps/myefiapp.efi,ready for execution.The GNU EFI build environment allows to write EFI applications asdescribed in Intel's EFI documentation, except for two differences: - The EFI application's entry point is always called "efi_main".  The   declaration of this routine is:    EFI_STATUS efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab); - UNICODE string literals must be written as W2U(L"Sample String")   instead of just L"Sample String".  The W2U() macro is defined in   <efilib.h>.  This header file also declares the function W2UCpy()   which allows to convert a wide string into a UNICODE string and   store the result in a programmer-supplied buffer. - Calls to EFI services should be made via uefi_call_wrapper(). This   ensures appropriate parameter passing for the architecture.* Part 2: Inner WorkingsWARNING: This part contains all the gory detail of how the GNU EFItoolchain works.  Normal users do not have to worry about suchdetails.  Reading this part incurs a definite risk of inducing severeheadaches or other maladies.The basic idea behind the GNU EFI build environment is to use the GNUtoolchain to build a normal ELF binary that, at the end, is convertedto an EFI binary.  EFI binaries are really just PE32+ binaries.  PEstands for "Portable Executable" and is the object file formatMicrosoft is using on its Windows platforms.  PE is basically the COFFobject file format with an MS-DOS2.0 compatible header slapped on infront of it.  The "32" in PE32+ stands for 32 bits, meaning that PE32is a 32-bit object file format.  The plus in "PE32+" indicates thatthis format has been hacked to allow loading a 4GB binary anywhere ina 64-bit address space (unlike ELF64, however, this is not a full64-bit object file format because the entire binary cannot span morethan 4GB of address space).  EFI binaries are plain PE32+ binariesexcept that the "subsystem id" differs from normal Windows binaries.There are two flavors of EFI binaries: "applications" and "drivers"and each has there own subsystem id and are identical otherwise.  Atpresent, the GNU EFI build environment supports the building of EFIapplications only, though it would be trivial to generate drivers, asthe only difference is the subsystem id.  For more details on PE32+,see the spec at	http://msdn.microsoft.com/library/specs/msdn_pecoff.htm.In theory, converting a suitable ELF64 binary to PE32+ is easy andcould be accomplished with the "objcopy" utility by specifying option--target=efi-app-ia32 (x86) or --target=efi-app-ia64 (IA-64).  Butlife never is that easy, so here some complicating factors: (1) COFF sections are very different from ELF sections.	ELF binaries distinguish between program headers and sections.	The program headers describe the memory segments that need to	be loaded/initialized, whereas the sections describe what	constitutes those segments.  In COFF (and therefore PE32+) no	such distinction is made.  Thus, COFF sections need to be page	aligned and have a size that is a multiple of the page size	(4KB for EFI), whereas ELF allows sections at arbitrary	addresses and with arbitrary sizes. (2) EFI binaries should be relocatable.	Since EFI binaries are executed in physical mode, EFI cannot	guarantee that a given binary can be loaded at its preferred	address.  EFI does _try_ to load a binary at it's preferred	address, but if it can't do so, it will load it at another	address and then relocate the binary using the contents of the	.reloc section. (3) On IA-64, the EFI entry point needs to point to a function     descriptor, not to the code address of the entry point. (4) The EFI specification assumes that wide characters use UNICODE     encoding.	ANSI C does not specify the size or encoding that a wide	character uses.  These choices are "implementation defined".	On most UNIX systems, the GNU toolchain uses a wchar_t that is	4 bytes in size.  The encoding used for such characters is	(mostly) UCS4.In the following sections, we address how the GNU EFI buildenvironment addresses each of these issues.** (1) Accommodating COFF SectionsIn order to satisfy the COFF constraint of page-sized and page-alignedsections, the GNU EFI build environment uses the special linker scriptin gnuefi/elf_$(ARCH)_efi.lds where $(ARCH) is the target architecture("ia32" for x86, "x86_64" for x86_64 and "ia64" for IA-64).This script is set up to create only eight COFF section, each page alignedand page sized.These eight sections are used to group together the muchgreater number of sections that are typically present in ELF object files.Specifically: .hash (and/or .gnu.hash)	Collects the ELF .hash info (this section _must_ be the first	section in order to build a shared object file; the section is	not actually loaded or used at runtime).	GNU binutils provides a mechanism to generate different hash info	via --hash-style=<sysv|gnu|both> option. In this case output	shared object will contain .hash section, .gnu.hash section or	both. In order to generate correct output linker script preserves	both types of hash sections. .text	Collects all sections containing executable code. .data	Collects read-only and read-write data, literal string data,	global offset tables, the uninitialized data segment (bss) and	various other sections containing data.	The reason read-only data is placed here instead of the in	.text is to make it possible to disassemble the .text section	without getting garbage due to read-only data.  Besides, since	EFI binaries execute in physical mode, differences in page	protection do not matter.	The reason the uninitialized data is placed in this section is	that the EFI loader appears to be unable to handle sections	that are allocated but not loaded from the binary. .dynamic, .dynsym, .rela, .rel, .reloc	These sections contains the dynamic information necessary to	self-relocate the binary (see below).A couple of more points worth noting about the linker script: o On IA-64, the global pointer symbol (__gp) needs to be placed such   that the _entire_ EFI binary can be addressed using the signed   22-bit offset that the "addl" instruction affords.  Specifically,   this means that __gp should be placed at ImageBase + 0x200000.   Strictly speaking, only a couple of symbols need to be addressable   in this fashion, so with some care it should be possible to build   binaries much larger than 4MB.  To get a list of symbols that need   to be addressable in this fashion, grep the assembly files in   directory gnuefi for the string "@gprel". o The link address (ImageBase) of the binary is (arbitrarily) set to   zero.  This could be set to something larger to increase the chance   of EFI being able to load the binary without requiring relocation.   However, a start address of 0 makes debugging a wee bit easier   (great for those of us who can add, but not subtract... ;-). o The relocation related sections (.dynamic, .rel, .rela, .reloc)   cannot be placed inside .data because some tools in the GNU   toolchain rely on the existence of these sections. o Some sections in the ELF binary intentionally get dropped when   building the EFI binary.  Particularly noteworthy are the dynamic   relocation sections for the .plabel and .reloc sections.  It would   be _wrong_ to include these sections in the EFI binary because it   would result in .reloc and .plabel being relocated twice (once by   the EFI loader and once by the self-relocator; see below for a   description of the latter).  Specifically, only the sections   mentioned with the -j option in the final "objcopy" command are   retained in the EFI binary (see Make.rules).** (2) Building Relocatable BinariesELF binaries are normally linked for a fixed load address and are thusnot relocatable.  The only kind of ELF object that is relocatable areshared objects ("shared libraries").  However, even those objects areusually not completely position independent and therefore requireruntime relocation by the dynamic loader.  For example, IA-64 binariesnormally require relocation of the global offset table.The approach to building relocatable binaries in the GNU EFI buildenvironment is to: (a) build an ELF shared object (b) link it together with a self-relocator that takes care of     applying the dynamic relocations that may be present in the     ELF shared object (c) convert the resulting image to an EFI binaryThe self-relocator is of course architecture dependent.  The x86version can be found in gnuefi/reloc_ia32.c, the x86_64 versioncan be found in gnuefi/reloc_x86_64.c and the IA-64 version can befound in gnuefi/reloc_ia64.S.The self-relocator operates as follows: the startup code invokes itright after EFI has handed off control to the EFI binary at symbol"_start".  Upon activation, the self-relocator searches the .dynamicsection (whose starting address is given by symbol _DYNAMIC) for thedynamic relocation information, which can be found in the DT_REL,DT_RELSZ, and DT_RELENT entries of the dynamic table (DT_RELA,DT_RELASZ, and DT_RELAENT in the case of rela relocations, as is thecase for IA-64).  The dynamic relocation information points to the ELFrelocation table.  Once this table is found, the self-relocator walksthrough it, applying each relocation one by one.  Since the EFIbinaries are fully resolved shared objects, only a subset of allpossible relocations need to be supported.  Specifically, on x86 onlythe R_386_RELATIVE relocation is needed.  On IA-64, the relocationsR_IA64_DIR64LSB, R_IA64_REL64LSB, and R_IA64_FPTR64LSB are needed.Note that the R_IA64_FPTR64LSB relocation requires access to thedynamic symbol table.  This is why the .dynsym section is included inthe EFI binary.  Another complication is that this relocation requiresmemory to hold the function descriptors (aka "procedure labels" or"plabels").  Each function descriptor uses 16 bytes of memory.  TheIA-64 self-relocator currently reserves a static memory area that canhold 100 of these descriptors.  If the self-relocator runs out ofspace, it causes the EFI binary to fail with error code 5(EFI_BUFFER_TOO_SMALL).  When this happens, the manifest constantMAX_FUNCTION_DESCRIPTORS in gnuefi/reloc_ia64.S should be increasedand the application recompiled.  An easy way to count the number offunction descriptors required by an EFI application is to run thecommand:  objdump --dynamic-reloc example.so | fgrep FPTR64 | wc -lassuming "example" is the name of the desired EFI application.** (3) Creating the Function Descriptor for the IA-64 EFI BinariesAs mentioned above, the IA-64 PE32+ format assumes that the entrypoint of the binary is a function descriptor.  A function descriptorsconsists of two double words: the first one is the code entry pointand the second is the global pointer that should be loaded beforecalling the entry point.  Since the ELF toolchain doesn't know how togenerate a function descriptor for the entry point, the startup codein gnuefi/crt0-efi-ia64.S crafts one manually by with the code:	        .section .plabel, "a"	_start_plabel:	        data8   _start	        data8   __gpthis places the procedure label for entry point _start in a sectioncalled ".plabel".  Now, the only problem is that _start and __gp needto be relocated _before_ EFI hands control over to the EFI binary.Fortunately, PE32+ defines a section called ".reloc" that can achievethis.  Thus, in addition to manually crafting the function descriptor,the startup code also crafts a ".reloc" section that has will causethe EFI loader to relocate the function descriptor before handing overcontrol to the EFI binary (again, see the PECOFF spec mentioned abovefor details).A final question may be why .plabel and .reloc need to go in their ownCOFF sections.  The answer is simply: we need to be able to discardthe relocation entries that are generated for these sections.  Byplacing them in these sections, the relocations end up in sections".rela.plabel" and ".rela.reloc" which makes it easy to filter themout in the filter script.  Also, the ".reloc" section needs to be inits own section so that the objcopy program can recognize it and cancreate the correct directory entries in the PE32+ binary.** (4) Convenient and Portable Generation of UNICODE String LiteralsAs of gnu-efi-3.0, we make use (and somewhat abuse) the gcc optionthat forces wide characters (WCHAR_T) to use short integers (2 bytes) instead of integers (4 bytes). This way we match the Unicode charactersize. By abuse, we mean that we rely on the fact that the regular ASCIIcharacters are encoded the same way between (short) wide characters and Unicode and basically only use the first byte. This allows usto just use them interchangeably.The gcc option to force short wide characters is : -fshort-wchar			* * * The End * * *
 |