Re-format README

* Make it look right in Markdown format
* Fix PE32+ spec link

Signed-off-by: Callum Farmer <gmbr3@opensuse.org>
This commit is contained in:
Callum Farmer 2024-09-06 16:11:33 +01:00
parent 2a3244d2e5
commit dfc27f3416
No known key found for this signature in database
GPG Key ID: 9A5B19E18CD0013C

151
README.md
View File

@ -1,18 +1,19 @@
------------------------------------------------- -------------------------------------------------
Building EFI Applications Using the GNU Toolchain Building EFI Applications Using the GNU Toolchain
------------------------------------------------- -------------------------------------------------
David Mosberger <davidm@hpl.hp.com> David Mosberger <davidm@hpl.hp.com>
23 September 1999 23 September 1999
Copyright (c) 1999-2007 Hewlett-Packard Co. Copyright (c) 1999-2007 Hewlett-Packard Co.
Copyright (c) 2006-2010 Intel Co.
Copyright (c) 2006-2010 Intel Co.
Last update (DD/MM/YYYY): 19/08/2024 Last update (DD/MM/YYYY): 19/08/2024
* Introduction # Introduction
This document has two parts: the first part describes how to develop 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 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: 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!) - 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, 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. but the Redhat 9.0 toolchain is not currently supported.
- A version of "objcopy" that supports EFI applications. To - A version of "objcopy" that supports EFI applications. To
check if your version includes EFI support, issue the check if your version includes EFI support, issue the
command: 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 - For debugging purposes, it's useful to have a version of
"efi-app-ia32" and "efi-app-x86_64" and that the "-j" option "objdump" that supports EFI applications as well. This
accepts wildcards. The binutils release binutils-2.24 allows inspect and disassemble EFI binaries.
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: To develop IA-64 EFI applications, the following tools are needed:
- A version of gcc newer than July 30th 1999 (older versions - A version of gcc newer than July 30th 1999 (older versions
had problems with generating position independent code). had problems with generating position independent code).
As of gnu-efi-3.0b, gcc-3.1 is known to work well. As of gnu-efi-3.0b, gcc-3.1 is known to work well.
- A version of "objcopy" that supports EFI applications. To - A version of "objcopy" that supports EFI applications. To
check if your version includes EFI support, issue the check if your version includes EFI support, issue the
command: 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 - For debugging purposes, it's useful to have a version of
"efi-app-ia64" and that the "-j" option accepts wildcards. "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 This EFI development environment contains the following
subdirectories: 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 files are taken from Intel's EFI source distribution, except
that various fixes were applied to make it compile with the that various fixes were applied to make it compile with the
GNU toolchain. 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 Again, the files are taken from Intel's EFI source
distribution, with changes to make them compile with the GNU distribution, with changes to make them compile with the GNU
toolchain. 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 binaries to EFI binaries. Various runtime code bits, such as
a self-relocator are included as well. This code has been a self-relocator are included as well. This code has been
contributed by the Hewlett-Packard Company and is distributed contributed by the Hewlett-Packard Company and is distributed
under the GNU GPL. 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 It is necessary to edit the Makefile in the directory containing this
README file before EFI applications can be built. Specifically, you 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"). the make command line (e.g., "make ARCH=ia64").
** Building ## Building
To build the sample EFI applications provided in subdirectory "apps", To build the sample EFI applications provided in subdirectory "apps",
simply invoke "make" in the toplevel directory (the directory 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. apps/t6.efi.
** Running ## Running
Just copy the EFI application (e.g., apps/t6.efi) to the EFI Just copy the EFI application (e.g., apps/t6.efi) to the EFI
filesystem, boot EFI, and then select "Invoke EFI application" to run 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. 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 Suppose you have your own EFI application in a file called
"apps/myefiapp.c". To get this application built by the GNU EFI build "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. 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 WARNING: This part contains all the gory detail of how the GNU EFI
toolchain works. Normal users do not have to worry about such 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 present, the GNU EFI build environment supports the building of EFI
applications only, though it would be trivial to generate drivers, as applications only, though it would be trivial to generate drivers, as
the only difference is the subsystem id. For more details on PE32+, the only difference is the subsystem id. For more details on PE32+,
see the spec at see the [Specification](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format).
http://msdn.microsoft.com/library/specs/msdn_pecoff.htm.
In theory, converting a suitable ELF64 binary to PE32+ is easy and In theory, converting a suitable ELF64 binary to PE32+ is easy and
could be accomplished with the "objcopy" utility by specifying option could be accomplished with the "objcopy" utility by specifying option
--target=efi-app-ia32 (x86) or --target=efi-app-ia64 (IA-64). But --target=efi-app-ia32 (x86) or --target=efi-app-ia64 (IA-64). But
life never is that easy, so here some complicating factors: 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. ELF binaries distinguish between program headers and sections.
The program headers describe the memory segments that need to 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 (4KB for EFI), whereas ELF allows sections at arbitrary
addresses and with arbitrary sizes. 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 Since EFI binaries are executed in physical mode, EFI cannot
guarantee that a given binary can be loaded at its preferred 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 address and then relocate the binary using the contents of the
.reloc section. .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. 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. encoding.
ANSI C does not specify the size or encoding that a wide 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. 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 In order to satisfy the COFF constraint of page-sized and page-aligned
sections, the GNU EFI build environment uses the special linker script 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. greater number of sections that are typically present in ELF object files.
Specifically: Specifically:
.text - .text
Collects all sections containing executable code. Collects all sections containing executable code.
.data - .data
Collects read-write data, literal string data, Collects read-write data, literal string data,
global offset tables, the uninitialized data segment (bss) global offset tables, the uninitialized data segment (bss)
and various other sections containing data. and various other sections containing data.
@ -243,7 +240,8 @@ Specifically:
that the EFI loader appears to be unable to handle sections that the EFI loader appears to be unable to handle sections
that are allocated but not loaded from the binary. that are allocated but not loaded from the binary.
.rodata - .rodata
Collects read-only data to retain the correct memory Collects read-only data to retain the correct memory
permissions permissions
@ -253,14 +251,16 @@ Specifically:
EFI binaries execute in physical mode, differences in page EFI binaries execute in physical mode, differences in page
protection do not matter. protection do not matter.
.dynamic, .rela, .rel, .reloc, .areloc - .dynamic, .rela, .rel, .reloc, .areloc
These sections contains the dynamic information necessary to These sections contains the dynamic information necessary to
self-relocate the binary (see below). 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 Collects the ELF .hash info (this section _must_ be the first
section in order to build a shared object file; the section is section in order to build a shared object file; the section is
not actually loaded or used at runtime). not actually loaded or used at runtime).
@ -271,13 +271,14 @@ Unnecessary sections:
both. In order to generate correct output linker script preserves both. In order to generate correct output linker script preserves
both types of hash sections. both types of hash sections.
.dynsym, .symtab - .dynsym, .symtab
The symbol tables used for ELF debugging The symbol tables used for ELF debugging
A couple of more points worth noting about the linker script: 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 that the _entire_ EFI binary can be addressed using the signed
22-bit offset that the "addl" instruction affords. Specifically, 22-bit offset that the "addl" instruction affords. Specifically,
this means that __gp should be placed at ImageBase + 0x200000. 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 to be addressable in this fashion, grep the assembly files in
directory gnuefi for the string "@gprel". 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 zero. This could be set to something larger to increase the chance
of EFI being able to load the binary without requiring relocation. of EFI being able to load the binary without requiring relocation.
However, a start address of 0 makes debugging a wee bit easier However, a start address of 0 makes debugging a wee bit easier
(great for those of us who can add, but not subtract... ;-). (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 cannot be placed inside .data because some tools in the GNU
toolchain rely on the existence of these sections. 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 building the EFI binary. Particularly noteworthy are the dynamic
relocation sections for the .plabel and .reloc sections. It would relocation sections for the .plabel and .reloc sections. It would
be _wrong_ to include these sections in the EFI binary because it 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). 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 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 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 The approach to building relocatable binaries in the GNU EFI build
environment is to: 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 applying the dynamic relocations that may be present in the
ELF shared object 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 The self-relocator is of course architecture dependent. The x86
version can be found in gnuefi/reloc_ia32.c, the x86_64 version 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 function descriptors required by an EFI application is to run the
command: 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. 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 As mentioned above, the IA-64 PE32+ format assumes that the entry
point of the binary is a function descriptor. A function descriptors 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. 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 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) 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 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 'u' string literals instead hence avoiding abuse of short wide characters
* * * The End * * * ***The End***