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:
parent
2a3244d2e5
commit
dfc27f3416
119
README.md
119
README.md
@ -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
|
Verify that the line "supported targets" contains the string
|
||||||
"efi-app-ia32" and "efi-app-x86_64" and that the "-j" option
|
"efi-app-ia32" and "efi-app-x86_64" and that the "-j" option
|
||||||
accepts wildcards. The binutils release binutils-2.24
|
accepts wildcards. The binutils release binutils-2.24
|
||||||
supports Intel64 EFI and accepts wildcard section names.
|
supports Intel64 EFI and accepts wildcard section names.
|
||||||
|
|
||||||
- For debugging purposes, it's useful to have a version of
|
- For debugging purposes, it's useful to have a version of
|
||||||
"objdump" that supports EFI applications as well. This
|
"objdump" that supports EFI applications as well. This
|
||||||
allows inspect and disassemble EFI binaries.
|
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
|
Verify that the line "supported targets" contains the string
|
||||||
"efi-app-ia64" and that the "-j" option accepts wildcards.
|
"efi-app-ia64" and that the "-j" option accepts wildcards.
|
||||||
|
|
||||||
- For debugging purposes, it's useful to have a version of
|
- For debugging purposes, it's useful to have a version of
|
||||||
"objdump" that supports EFI applications as well. This
|
"objdump" that supports EFI applications as well. This
|
||||||
allows inspect and disassemble EFI binaries.
|
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***
|
||||||
|
Loading…
Reference in New Issue
Block a user