| This page describes the process that the SeaBIOS build uses to link |
| the compiled code into the final binary objects. |
| |
| Unfortunately, the SeaBIOS linking phase is complex. This complexity |
| is due to several unusual requirements: |
| |
| * Some BIOS entry points must reside at specific hardcoded memory |
| locations. The build must support positioning code and variables at |
| specific locations. |
| * In order to support multiple [memory models](Memory Model) the same |
| C code can be complied in three modes (16bit mode, 32bit segmented |
| mode, and 32bit "flat" mode). Binary code from these three modes |
| must be able to co-exist and on occasion reference each other. |
| * There is a finite amount of memory available to the BIOS. The build |
| will attempt to weed out unused code and variables from the final |
| binary. It also supports self-relocation of one-time initialization |
| code. |
| |
| Code layout |
| =========== |
| |
| To support the unusual build requirements, several |
| [gcc](http://en.wikipedia.org/wiki/GNU_Compiler_Collection) compiler |
| options are used. The "-ffunction-sections" and "-fdata-sections" |
| flags instruct the compiler to place each variable and function into |
| its own |
| [ELF](http://en.wikipedia.org/wiki/Executable_and_Linkable_Format) |
| section. |
| |
| The C code is compiled three times into three separate objects for |
| each of the major supported [memory models](Memory Model): |
| **code16.o**, **code32seg.o**, and **code32flat.o**. Information on |
| the sections and symbols of these three objects are extracted (using |
| **objdump**) and passed in to the **scripts/layoutrom.py** python |
| script. This script analyzes this information and produces gnu |
| [ld](http://en.wikipedia.org/wiki/GNU_linker) "linker scripts" which |
| provide precise location information to the linker. These linker |
| scripts are then used during the link phase which produces a **rom.o** |
| object containing all the code. |
| |
| Fixed location entry points |
| --------------------------- |
| |
| The build supports placing code entry points and variables at fixed |
| memory locations. This support is required in order to support the |
| legacy BIOS standards. For example, a program might execute an "int |
| 0x15" to request system information from the BIOS, but another old |
| program might use "ljmpw $0xf000, $0xf859" instead. Both must provide |
| the same results and so the build must position the 0x15 interrupt |
| entry point in physical memory at 0xff859. |
| |
| This support is accomplished by placing the given code/variables into |
| ELF sections that have a name containing the substring |
| ".fixedaddr.0x1234" (where 0x1234 is the desired address). For |
| variables in C code this is accomplished by marking the variables with |
| the VARFSEGFIXED(0x1234) macro. For assembler entry points the ORG |
| macro is used (see **romlayout.S**). |
| |
| During the build, the **layoutrom.py** script will detect sections |
| that contain the ".fixedaddr." substring and will arrange for the |
| final linker scripts to specify the desired address for the given |
| section. |
| |
| Due to the sparse nature of these fixed address sections, the |
| layoutrom.py script will also arrange to pack in other unrelated 16bit |
| code into the free space between fixed address sections (see |
| layoutrom.py:fitSections()). This maximizes the space available and |
| reduces the overall size of the final binary. |
| |
| C code in three modes |
| --------------------- |
| |
| SeaBIOS must support multiple [memory models](Memory Model). This is |
| accomplished by compiling the C code three separate times into three |
| separate objects. |
| |
| The C code within a mode must not accidentally call a C function in |
| another mode, but multiple modes must all access the same single copy |
| of global variables. Further, it is occasionally necessary for the C |
| code in one mode to obtain the address of C code in another mode. |
| |
| In order to use the same global variables between all modes, the |
| layoutrom.py script will detect references to global variables and |
| emit specific symbol definitions for those global variables in the |
| linker scripts so that all references use the same physical memory |
| address (see layoutrom.py:outXRefs()). |
| |
| To ensure C code does not accidentally call C code compiled in a |
| different mode, the build will ensure the symbols for C code in each |
| mode are isolated from each other during the linking stage. To support |
| those situations where an address of a C function in another mode is |
| required the build supports symbols with a special "\_cfuncX_" |
| prefix. The layoutrom.py script detects these references and will emit |
| a corresponding symbol definitions in the linker script that points to |
| the C code of the specified mode. The call32() and stack_hop_back() |
| macros automatically add the required prefix for C code, but the |
| prefixes need to be explicitly added in assembler code. |
| |
| Build garbage collection |
| ------------------------ |
| |
| To reduce the overall size of the final SeaBIOS binary the build |
| supports automatically weeding out of unused code and variables. This |
| is done with two separate processes: when supported the gcc |
| "-fwhole-program" compilation flag is used, and the layoutrom.py |
| script checks for unreferenced ELF sections. The layoutrom.py script |
| builds the final linker scripts with only referenced ELF sections, and |
| thus unreferenced sections are weeded out from the final objects. |
| |
| When writing C code, it is necessary to mark C functions with the |
| VISIBLE16, VISIBLE32SEG, or VISIBLE32FLAT macros if the functions are |
| ever referenced from assembler code. These macros ensure the |
| corresponding C function is emitted by the C compiler when compiling |
| for the given memory mode. These macros, however, do not affect the |
| layoutrom.py reference check, so even a function decorated with one of |
| the above macros can be weeded out from the final object if it is |
| never referenced. |
| |
| Code relocation |
| --------------- |
| |
| To further reduce the runtime memory size of the BIOS, the build |
| supports runtime self-relocation. Normally SeaBIOS is loaded into |
| memory in the memory region at 0xC0000-0x100000. This is convenient |
| for initial binary deployment, but the space competes with memory |
| requirements for Option ROMs, BIOS tables, and runtime storage. By |
| default, SeaBIOS will self-relocate its one-time initialization code |
| to free up space in this region. |
| |
| To support this feature, the build attempts to automatically detect |
| which C code is exclusively initialization phase code (see |
| layoutrom.py:checkRuntime()). It does this by finding all functions |
| decorated with the VISIBLE32INIT macro and all functions only |
| reachable via functions with that macro. These "init only" functions |
| are then grouped together and their location and size is stored in the |
| binary for the runtime code to relocate (see post.c:reloc_preinit()). |
| |
| The build also locates all cross section code references along with |
| all absolute memory addresses in the "init only" code. These addresses |
| need to be modified with the new run-time address in order for the |
| code to successfully run at a new address. The build finds the |
| location of the addresses (see layoutrom.py:getRelocs()) and stores |
| the information in the final binary. |
| |
| Final binary checks |
| =================== |
| |
| At the conclusion of the main linking stage, the code is contained in |
| the file **rom.o**. This object file contains all of the assembler |
| code, variables, and the C code from all three memory model modes. |
| |
| At this point the **scripts/checkrom.py** script is run to perform |
| final checks on the code. The script performs some sanity checks, it |
| may update some tables in the binary, and it reports some size |
| information. |
| |
| After the checkrom.py script is run the final user visible binary is |
| produced. The name of the final binary is either **bios.bin**, |
| **Csm16.bin**, or **bios.bin.elf** depending on the SeaBIOS build |
| requested. |