This toolset allows one to quickly port UEFI code to userspace utilities in popular operating systems such as macOS, Windows, or Linux. The only requirement is a C11-supporting compiler with the build scripts adopted for modern versions of clang and gcc.
Create a Makefile
with the contents similar to an example below:
PROJECT = ProjectName
PRODUCT = $(PROJECT)$(SUFFIX)
OBJS = $(PROJECT).o ExtraObject.o
VPATH = ../../Library/MyExtraLib:$
include ../../User/Makefile
CFLAGS += -I../../Library/MyExtraLib
Build it with the make
command.
Additional variables are supported to adjust the compilation process.
COVERAGE=1
— build with coverage information gathering.DEBUG=1
— build with debugging information.FUZZ=1
— build with fuzzing enabled.FUZZ_JOBS=2
— run with 2 fuzzing jobs (defaults to 4).FUZZ_MEM=1024
- run with 1024 MB fuzzing memory limit (defaults to 4096)*.SANITIZE=1
— build with LLVM sanitizers enabled.CC=cc
— build withcc
compiler (e.g.i686-w64-mingw32-gcc
for Windows).DIST=Target
— build for targetTarget
(e.g.Darwin
,Linux
,Windows
).STRIP=strip
— build withstrip
stripping tool (e.g.i686-w64-mingw32-strip
for Windows).OC_PATH
- path to OpenCorePkg for out-of-tree utilities (defaults to../..
).UDK_ARCH=Ia32
— build with 32-bit UDK architecture (defaults toX64
).UDK_PATH=/path/to/UDK
— build with custom UDK path (defaults to$PACKAGES_PATH
).WERROR=1
— treat compiler warnings as errors.SYDR=1
— change$(SUFFIX)
to store compilation results for Sydr DSE in a directory distinct from the default one.
*NOTE: If your program uses UserBaseMemoryLib
and calls custom allocation functions, be sure that besides FUZZ_MEM
limit you correctly set limit mPoolAllocationSizeLimit
which defaults to the 512 MB in cases if your code could allocate more than this limit at single AllocatePool.
To set up your limit, use SetPoolAllocationSizeLimit
routine like shown in the example below:
...
#include <UserMemory.h>
int main(int argc, char *argv[]) {
SetPoolAllocationSizeLimit (SINGLE_ALLOCATION_MEMORY_LIMIT);
/* your code goes here */
return 0;
}
Example 1. To build 32-bit version of utility on macOS (use High Sierra 10.13 or below):
UDK_ARCH=Ia32 make
Example 2. To build for 32-bit Windows (requires MinGW installed) use the following command:
UDK_ARCH=Ia32 CC=i686-w64-mingw32-gcc STRIP=i686-w64-mingw32-strip DIST=Windows make
Example 3. To build with LLVM sanitizers use the following command:
DEBUG=1 SANITIZE=1 make
Example 4. Perform fuzzing and generate coverage report:
# MacPorts clang is used since Xcode clang has no fuzzing support.
CC=clang-mp-10 FUZZ=1 SANITIZE=1 DEBUG=1 make fuzz
# LCOV is required for running this command.
make clean
COVERAGE=1 DEBUG=1 make coverage
Note: fuzzing corpus is saved in FUZZDICT
.
Example 5. Perform fuzzing with the help of Sydr tool (path to which should be in $PATH
):
CC=clang DEBUG=1 FUZZ=1 SANITIZE=1 make
CC=clang DEBUG=1 SYDR=1 make sydr-fuzz
# Optionally check for security predicates.
CC=clang DEBUG=1 SYDR=1 make sydr-fuzz-security
# Import Sydr inputs to FUZZDICT.
CC=clang DEBUG=1 SYDR=1 make sydr-fuzz-import
make clean
COVERAGE=1 DEBUG=1 make sydr-import-check
# LCOV is required for running this command.
make clean
COVERAGE=1 DEBUG=1 make coverage
Most UDK variables are available due to including the original headers.
- To distinguish target platform
MDE_CPU_*
variables can be used. For example,MDE_CPU_IA32
for 32-bit Intel andMDE_CPU_X64
for 64-bit Intel. - To distinguish from normal UEFI compilation use
EFIUSER
variable. - To detect debug build use
EFIUSER_DEBUG
variable. - To detect sanitizing status use
SANITIZE_TEST
. - To detect fuzzing status use
FUZZING_TEST
. - Use
ENTRY_POINT
variable formain
to automatically disable it for fuzzing.