- Go 95.8%
- Makefile 4.2%
| cmd/bbld | Handle Link() errors | |
| internal/link | Work on section merging | |
| testdata/minimal | Work on section merging | |
| .gitignore | Ignore .o16 | |
| go.mod | go mod tidy | |
| go.sum | Argument parsing | |
| LICENSE.md | Add license | |
| Makefile | Run bbld in test target | |
| README.md | Link license in readme | |
BRIDGES Binary Linker
See also: BRIDGES.ROM
bbld -o hello.exe hi-x86.o hi-8086.o16 hi-mips.o ... user32.dll ...
Links object files from multiple different architectures together in a polyglot binary that is a:
| Arch. | Format |
|---|---|
| x86-16 | BIOS bootable disk image |
| " | DOS .exe binary |
| x86-32 | Win32 .exe binary |
| Z80 | Game Boy ROM |
| ARM | Game Boy Advance ROM |
| " | Raspberry Pi kernel |
| 5A22 | Super Nintendo ROM |
| MIPS | PlayStation disc image (MIPS) |
...given that object files for the respective architectures are supplied.
This is possible because these specific targets' headers, magic markers, and entry points are expected at non-conflicting locations in the file, or careful crafting allows for overlapping sections that are valid (enough) for each. In particular, the very start of the file is a DOS MZ .exe header, x86-16 code, and ARM code.
Status
Earliest stages of project setup.
Usage
bbld [-o output.exe] files ...
Example:
arm-none-eabi-as -o start-arm.o start-arm.S
nasm -o start16.o start16.asm
nasm -o start32.o start32.asm
nasm -o data.o data.asm # architecture doesn't matter
bbld -o hello.exe start-arm.o start16.o start32.o data.o
File structure
The linker generates a file with the following general structure:
DOS MZ header / x86-16 trampoline / ARM trampoline
..code (MBR)..
Win32 PE header
Game Boy header
Game Boy Advance header
..
SNES header
ISO descriptors
..code..
..data..
The total file size is fixed at 512 KB.
Linking
The linker takes object files of any supported architecture (as
indicated by its machine field). A _start entry point must be defined
for each architecture in the input.
Input sections named .text(.*), .data(.*) and .bss(.*) are read.
It is important to realize that the polyglot binary consists of distinct
programs for each architecture. The linker combines them into a single
artefact, but does not offer abstractions or initialization code
(including .bss zeroing).
Objects of the same architecture are considered 'link units' together. This means that by default, symbols are only visible within the same architecture (ELF visibility 'hidden'). Public symbols, what would normally be library exports, are exported to all the object files of any architecture (ELF visibility 'default'). This allows for e.g. common data sections or cross-architecture jumps, such as x86-16 code entering protected mode and jumping to an exported x86-32 entry point.
To facilitate cross-architecture linking, all .text(.*) and
.data(.*) input sections are placed in one .text and .data output
section respectively, so that all code and data exists in all
architectures' address spaces.
The linker exports __text_start, __data_start, __bss_start and
__bss_end per-architecture, and __image_end (the very end, or size,
of the binary) globally.
Architectures
x86-16
Since ELF makes no distinction between x86-16 and x86-32 object files, x86-16
objects must have a .o16 extensions to be considered such by the linker.
The DOS .exe is set up with split code and data segment. All x86-16
.text(.*) goes in the code segment, all .data(.*) (of any
architecture) goes into the data segment. This easily exceeds the 64KB
maximum section size, so any input section referenced by x86-16 code is
moved to the front. The linker will emit an error when those exceed
64KB.
As an exception, the BIOS boot does not enter at _start, but at
_bios_start, to be defined in .text.mbr. This section will be placed
within the first 512 bytes of the file, read by the BIOS. This code will
have to load the rest of the binary from disk and set up segments to
match the DOS version.
x86-32
This runs as a fairly standard Win32 binary. Importing from DLLs is
supported, with their names supplied as input files (e.g.
user32.dll).
ARM
The Game Boy Advance uses ARMv4. The Raspberry Pi format is for ARMv7 (32-bit), which is backwards compatible with ARMv4. Hence, these are considered as one architecture for the purpose of this linker.
While they share an instruction set and entry point, these are very different environments, map the code to very different addresses, and the linker makes no effort to address this. [TBD: what base address is used and how to deal with that]
Z80 (Game Boy)
[TBD]
5A22 (SNES)
[TBD]
Author
Sijmen J. Mulder (ik@sjmulder.nl). See LICENSE.md.