blob: a7b47f936ef97c4927483788b7cab979823176bf [file] [edit]
============================
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.