1
0
Fork
You've already forked bbld
0
BRIDGES Binary Linker
  • Go 95.8%
  • Makefile 4.2%
Find a file
2026年04月19日 14:49:37 +02:00
cmd/bbld Handle Link() errors 2026年03月07日 19:06:06 +01:00
internal/link Work on section merging 2026年04月07日 08:26:00 +02:00
testdata/minimal Work on section merging 2026年04月07日 08:26:00 +02:00
.gitignore Ignore .o16 2026年03月08日 01:59:49 +01:00
go.mod go mod tidy 2026年03月07日 19:10:00 +01:00
go.sum Argument parsing 2026年03月07日 15:03:16 +01:00
LICENSE.md Add license 2026年04月19日 14:47:24 +02:00
Makefile Run bbld in test target 2026年04月04日 01:40:41 +02:00
README.md Link license in readme 2026年04月19日 14:49:37 +02:00

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.