| # Aligned Instruction Bundling | |
| ## Overview | |
| *Aligned instruction bundling* partitions the instructions in a section into | |
| fixed-size, naturally aligned groups called bundles, and guarantees that no | |
| instruction ever crosses a bundle boundary. Consecutive instructions can also | |
| be grouped so that the assembler guarantees the whole group resides within a | |
| single bundle. | |
| Bundling is a building block for software-based fault isolation (SFI) and | |
| sandboxing schemes. Forcing every instruction to begin at one of a statically | |
| known set of offsets gives the instruction stream a single canonical decoding: | |
| control flow cannot jump into the middle of an instruction to manufacture a | |
| different, unchecked instruction sequence. When combined with masking of | |
| indirect branch targets to bundle-aligned addresses, this constrains all | |
| control flow to a statically verifiable set of locations and instructions. | |
| Bundling is used by the x86-64 implementation of {doc}`Lightweight Fault | |
| Isolation (LFI) <LFI>`. | |
| :::{note} | |
| The current LLVM implementation supports bundling only for x86 ELF targets. | |
| Other targets and object file formats reject the directives below rather | |
| than emit unbundled code silently. | |
| ::: | |
| ## `.bundle_align_mode` | |
| ``` | |
| .bundle_align_mode abs-expr | |
| ``` | |
| Enables aligned bundle mode and sets the bundle size to `2^abs-expr` bytes, | |
| where `abs-expr` is a power-of-two exponent between 1 and 30 (as for the | |
| `.p2align` directive). For example, `.bundle_align_mode 5` selects 32-byte | |
| bundles. Unlike GNU as, `.bundle_align_mode 0` is rejected: bundling cannot be | |
| turned off once enabled. | |
| While bundling is enabled, the assembler ensures that no single instruction | |
| spans a boundary between two bundles. When an instruction would not fit in the | |
| space remaining in the current bundle, that space is filled with no-op | |
| instructions so the instruction starts at the beginning of the next bundle. | |
| Enabling bundle mode also raises the alignment of every text section that | |
| receives instructions to at least the bundle size. | |
| Once enabled, bundle mode stays in effect for the rest of the file and its | |
| bundle size is fixed. | |
| ## `.bundle_lock` and `.bundle_unlock` | |
| ``` | |
| .bundle_lock [align_to_end] | |
| ...instructions... | |
| .bundle_unlock | |
| ``` | |
| A `.bundle_lock` / `.bundle_unlock` pair encloses a sequence of | |
| instructions that must all be placed in a single bundle. The assembler inserts | |
| padding before the sequence, if necessary, so that the entire group lands | |
| within one bundle rather than straddling a boundary. | |
| The enclosed sequence must fit within a single bundle -- it is an error if the | |
| total size of the locked instructions exceeds the bundle size. | |
| Both directives are only valid in an executable section after bundle mode has | |
| been enabled with `.bundle_align_mode`. A `.bundle_unlock` must be matched | |
| by a preceding `.bundle_lock`, and a section may not be switched while a | |
| `.bundle_lock` is open. A group may not end in a bare instruction prefix, | |
| which the assembler could not keep attached to the instruction it modifies. | |
| ### `align_to_end` | |
| By default a locked group is padded at the front so that it starts far enough | |
| into the bundle to fit. With the `align_to_end` option the group is instead | |
| padded so that its last instruction ends exactly on a bundle boundary. | |
| ## Padding | |
| By default, bundle padding is emitted as no-op instructions, and neither an | |
| instruction nor a padding no-op is ever allowed to cross a bundle boundary. | |
| ### Prefix padding (x86) | |
| On x86 the assembler can instead absorb some of the required padding into | |
| neighboring instructions by prepending otherwise-ignored instruction prefixes | |
| to them, avoiding standalone no-ops. This is controlled by: | |
| :::{option} --x86-pad-max-prefix-size=<N> | |
| Maximum number of prefixes the assembler may add to an instruction for | |
| padding. `0` (the default) disables prefix padding, so only no-op | |
| instructions are used. | |
| ::: | |
| Padding is only ever traded for instruction bytes within the bundle that holds | |
| it, so this cannot move an instruction or a locked group across a boundary. It | |
| does change where labels land, so it may break assumptions about labels | |
| corresponding to particular instructions. | |