This folder contains some examples that show a different way of compiling source code for the Morello targets. This way is commonly referred to as "hybrid". CHERI capabilities implement source-level pointers (or references) on the machine level. An integer pointer (address-only pointer) is another implementation of references. When compiling for the Morello target, one of these two implementations should be default while another would be alternative. The default implementation does not require any source changes while alternative implementation must be annotated on the source level.
| Mode | Default T& and T* |
Alternative T& and T* |
ISA |
|---|---|---|---|
| Hybrid | Address | Capability | A64 |
| Purecap | Capability | Address | C64 |
When you compile source code for the Morello target, you select which compilation
mode is used (by specifying corresponding compilation flags) and this affects how
the T& and T* language-level entities are interpreted and converted into the
machine-level implementation. In a nutshell, in the Hybrid mode all pointers are
addresses unless annotated as capabilities while in the Purecap mode all pointers
are capabilities:
// Hybrid code:
char *ptr = "string"; // address (sizeof(char *) is 8)
char *__capability cap = "string"; // capability (sizeof(char *__capability) is 16)
When compiling in Hybrid mode, the machine code is generated for the A64 ISA mode
and in Purecap compilation mode the intended ISA mode is C64. However, ISA mode
and the interpretation of language-level pointers are orthogonal. Moreover, the
actual ISA mode depends on the CPU runtime state (the PSTATE.C64 bit) while the
binary code generated once would stay the same and would be just interpreted in
a different way. For example, the following instruction encoding 0xc2400020 will
be interpreted in a different way depending on the PSTATE.C64 bit:
ldr c0, [x1, #0] // (PSTATE.C64 == 0)
ldr c0, [c1, #0] // (PSTATE.C64 == 1)
Both interpretations load a capability into the C0 register using address from
either X1 register or C1 register. In both cases memory access will be done
via a capability. In the former case this capability will be derived from the
default data capability DDC using the address stored in the X1 register. In
the latter case the capability in the C1 register will be explicitly used.
Using hybrid compilation objects one can implement a particular memory access via
an explicitly declared capability while the rest of the memory accesses may remain
carried out via the DDC capability. Hybrid compilation mode allows for gradual
introduction of capabilities into your code.
In Purecap mode all pointers are treated as capabilities by default. The scheme discussed above allows for an alternative form of a pointer in Purecap that would be just an integer address (as in the default pointer interpretation in Hybrid), however it is not yet implemented. It is not yet possible to express such a pointer on a C language level, although you can use integer addresses on assembly level.
Although Hybrid mode allows you to declare a pointer as a capability and then use it to control memory accesses, in practice you will most likely need your runtime (e.g. C library or dynamic linker) to be capability-aware. The following list may be used as a starting point for producing a so-called hybrid C library for CHERI or Morello. Note that this is not an exhaustive list and that some of these features may not be implemented at all.
R_MORELLO_RELATIVE).getauxptr function to access capabilities in auxv.memcpy function and friends should use capability loads and stores to
preserve capability tags if present.malloc and mmap and friends should support
returning bounded capabilities instead of raw addresses. A similar change
is required for free and munmap as well as for realloc and mremap.A compiler that supports Hybrid mode of compilation should deduce bounds and permissions
for explicitly declared capabilities pointing to objects with automatic storage. The
same should apply to alloca results.