diff --git a/README.md b/README.md index d9e19a3..babb2d6 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,19 @@ - ------------------------------------------------- - Building EFI Applications Using the GNU Toolchain - ------------------------------------------------- +------------------------------------------------- +Building EFI Applications Using the GNU Toolchain +------------------------------------------------- - David Mosberger +David Mosberger - 23 September 1999 +23 September 1999 - Copyright (c) 1999-2007 Hewlett-Packard Co. - Copyright (c) 2006-2010 Intel Co. +Copyright (c) 1999-2007 Hewlett-Packard Co. + +Copyright (c) 2006-2010 Intel Co. Last update (DD/MM/YYYY): 19/08/2024 -* Introduction +# Introduction This document has two parts: the first part describes how to develop EFI applications for IA-64,x86 and x86_64 using the GNU toolchain and the EFI @@ -22,76 +23,72 @@ environment works. -* Part 1: Developing EFI Applications +# Part 1: Developing EFI Applications -** Prerequisites: +## 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. +- 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: +- A version of "objcopy" that supports EFI applications. To + check if your version includes EFI support, issue the + command: `objcopy --help` - 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. - 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. +- 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 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: +- A version of "objcopy" that supports EFI applications. To + check if your version includes EFI support, issue the + command: `objcopy --help` - objcopy --help + Verify that the line "supported targets" contains the string + "efi-app-ia64" and that the "-j" option accepts wildcards. - 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. +- 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 Structure +## Directory Structure This EFI development environment contains the following subdirectories: - inc: This directory contains the EFI-related include files. The + - 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. + - 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 + - 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. + - apps: This directory contains a few simple EFI test apps. -** Setup +## Setup It is necessary to edit the Makefile in the directory containing this README file before EFI applications can be built. Specifically, you @@ -105,7 +102,7 @@ x86_64 and "ia64" for IA-64). For convenience, this can also be done from the make command line (e.g., "make ARCH=ia64"). -** Building +## Building To build the sample EFI applications provided in subdirectory "apps", simply invoke "make" in the toplevel directory (the directory @@ -114,7 +111,7 @@ gnuefi/libgnuefi.a first and then all the EFI applications such as a apps/t6.efi. -** Running +## Running Just copy the EFI application (e.g., apps/t6.efi) to the EFI filesystem, boot EFI, and then select "Invoke EFI application" to run @@ -123,7 +120,7 @@ Intel-provided "nshell" application and then invoke your test binary via the command line interface that "nshell" provides. -** Writing Your Own EFI Application +## Writing Your Own EFI Application Suppose you have your own EFI application in a file called "apps/myefiapp.c". To get this application built by the GNU EFI build @@ -150,7 +147,7 @@ described in Intel's EFI documentation, except for two differences: ensures appropriate parameter passing for the architecture. -* Part 2: Inner Workings +# Part 2: Inner Workings WARNING: This part contains all the gory detail of how the GNU EFI toolchain works. Normal users do not have to worry about such @@ -175,16 +172,14 @@ and each has there own subsystem id and are identical otherwise. At present, the GNU EFI build environment supports the building of EFI applications only, though it would be trivial to generate drivers, as the only difference is the subsystem id. For more details on PE32+, -see the spec at - - http://msdn.microsoft.com/library/specs/msdn_pecoff.htm. +see the [Specification](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format). In theory, converting a suitable ELF64 binary to PE32+ is easy and could be accomplished with the "objcopy" utility by specifying option --target=efi-app-ia32 (x86) or --target=efi-app-ia64 (IA-64). But life never is that easy, so here some complicating factors: - (1) COFF sections are very different from ELF sections. + 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 @@ -195,7 +190,7 @@ life never is that easy, so here some complicating factors: (4KB for EFI), whereas ELF allows sections at arbitrary addresses and with arbitrary sizes. - (2) EFI binaries should be relocatable. + 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 @@ -204,10 +199,10 @@ life never is that easy, so here some complicating factors: 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 + 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 + 4. The EFI specification assumes that wide characters use UNICODE encoding. ANSI C does not specify the size or encoding that a wide @@ -220,7 +215,7 @@ In the following sections, we address how the GNU EFI build environment addresses each of these issues. -** (1) Accommodating COFF Sections +## (1) Accommodating COFF Sections In order to satisfy the COFF constraint of page-sized and page-aligned sections, the GNU EFI build environment uses the special linker script @@ -231,10 +226,12 @@ and page sized.These eight sections are used to group together the much greater number of sections that are typically present in ELF object files. Specifically: - .text + - .text + Collects all sections containing executable code. - .data + - .data + Collects read-write data, literal string data, global offset tables, the uninitialized data segment (bss) and various other sections containing data. @@ -243,7 +240,8 @@ Specifically: that the EFI loader appears to be unable to handle sections that are allocated but not loaded from the binary. -.rodata +- .rodata + Collects read-only data to retain the correct memory permissions @@ -253,14 +251,16 @@ Specifically: EFI binaries execute in physical mode, differences in page protection do not matter. - .dynamic, .rela, .rel, .reloc, .areloc + - .dynamic, .rela, .rel, .reloc, .areloc + These sections contains the dynamic information necessary to self-relocate the binary (see below). -Unnecessary sections: +### Unnecessary sections: + +- .hash (and/or .gnu.hash) -.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). @@ -271,13 +271,14 @@ Unnecessary sections: both. In order to generate correct output linker script preserves both types of hash sections. -.dynsym, .symtab +- .dynsym, .symtab + The symbol tables used for ELF debugging 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 + - 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. @@ -287,17 +288,17 @@ A couple of more points worth noting about the linker script: 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 + - 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) + - 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 + - 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 @@ -308,7 +309,7 @@ A couple of more points worth noting about the linker script: retained in the EFI binary (see Make.rules). -** (2) Building Relocatable Binaries +## (2) Building Relocatable Binaries ELF binaries are normally linked for a fixed load address and are thus not relocatable. The only kind of ELF object that is relocatable are @@ -320,13 +321,13 @@ normally require relocation of the global offset table. The approach to building relocatable binaries in the GNU EFI build environment is to: - (a) build an ELF shared object + 1. build an ELF shared object - (b) link it together with a self-relocator that takes care of + 2. 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 binary + 3. convert the resulting image to an EFI binary The self-relocator is of course architecture dependent. The x86 version can be found in gnuefi/reloc_ia32.c, the x86_64 version @@ -361,12 +362,12 @@ and the application recompiled. An easy way to count the number of function descriptors required by an EFI application is to run the command: - objdump --dynamic-reloc example.so | fgrep FPTR64 | wc -l +`objdump --dynamic-reloc example.so | fgrep FPTR64 | wc -l` assuming "example" is the name of the desired EFI application. -** (3) Creating the Function Descriptor for the IA-64 EFI Binaries +## (3) Creating the Function Descriptor for the IA-64 EFI Binaries As mentioned above, the IA-64 PE32+ format assumes that the entry point of the binary is a function descriptor. A function descriptors @@ -401,7 +402,7 @@ its own section so that the objcopy program can recognize it and can create the correct directory entries in the PE32+ binary. -** (4) Convenient and Portable Generation of UNICODE String Literals +## (4) Convenient and Portable Generation of UNICODE String Literals From gnu-efi-3.0, we made use (and somewhat abused) the gcc option that forces wide characters (WCHAR_T) to use short integers (2 bytes) @@ -416,4 +417,4 @@ The gcc option to force short wide characters is : -fshort-wchar We have since defined CHAR16 to be char16_t which allows us to use the C11 'u' string literals instead hence avoiding abuse of short wide characters - * * * The End * * * +***The End***