This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Build failed for a baremetal

hello,

While I am trying to execute a simple bubble sort program in c as provided as an example in the arm development studio IDE, I am facing 3 errors like as shown below:  (Target and source must be capability)

/bubblesort.c:45:37: error: invalid target type 'uint32_t *' (aka 'unsigned int *') for __cheri_tocap: target must be a capability
    seq_t sequence = (__cheri_tocap seq_t)malloc(sizeof(uint32_t) * SEQ_LEN);

../bubblesort.c:57:33: error: invalid source type 'uint32_t *' (aka 'unsigned int *') for __cheri_fromcap: source must be a capability
    free((__cheri_fromcap void*)sequence);

/bubblesort.c:70:6: error: conflicting types for 'print'
void print (seq_t __cheri_input sequence, int size) {

N.B: I am using LLVM 13.0.0 with Morello support.

Parents
  • Hello,

    I am trying to compile (using llvm release 1.6 for baremetal) a standalone bare-metal program of the bubblesort as shown before, and not using CHERIBSD in purecap mode. However, I am getting the same error with target and souce must be a capability:

    bubblesort_cam.c:123:37: error: invalid target type 'uint32_t *' (aka 'unsigned int *') for __cheri_tocap: target must be a capability
        seq_t sequence = (__cheri_tocap seq_t)malloc(sizeof(uint32_t) * SEQ_LEN);
                                        ^
    bubblesort_cam.c:106:15: note: expanded from macro 'seq_t'
    #define seq_t uint32_t*__capability
                  ^
    bubblesort_cam.c:135:33: error: invalid source type 'uint32_t *' (aka 'unsigned int *') for __cheri_fromcap: source must be a capability
        free((__cheri_fromcap void*)sequence);

    I am using the linker script from the one in the below link:

    git.morello-project.org/.../standalone-baremetal-readme.rst

    N.B: Since it is a standalone baremetal program I already commented out the print statements and I have enclosed the cheri.h file code below. This header file is already provided in the sample example of ARM MORELLO.

    ============bubblesort.c   code below====================================

    //==========bubblesort=============
    
    #include <stdio.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <time.h>
    #include "cheri.h"
    
    
    #define seq_t uint32_t*__capability
    
    // The __capability qualifier here is not necessary when compiling for "pure" mode
    // (because all pointers have capabilities in "pure" mode), but might be needed
    // if compiling for "hybrid" mode, so has been left in for convenience and clarity.
    
    #define SEQ_LEN 15
    
    void populate (seq_t __cheri_output sequence, int size);
    void sort (seq_t sequence, int size);
    void swap (seq_t first, seq_t second);
    
    
    int main (void) {
        //printf("Morello bare-metal bubble sort example\n\n");
    
        seq_t sequence = (__cheri_tocap seq_t)malloc(sizeof(uint32_t) * SEQ_LEN);
    
        populate(sequence, SEQ_LEN);
    
        //printf("Original sequence:\n  ");
        //print(sequence, SEQ_LEN);
    
        sort(sequence, SEQ_LEN);
    
        //printf("Sorted sequence:\n  ");
        //print(sequence, SEQ_LEN);
    
        free((__cheri_fromcap void*)sequence);
    
        return 0;
    }
    
    void populate (seq_t __cheri_output sequence, int size) {
        srand(time(NULL));
    
        for (int i = 0; i < size; i++) {
            sequence[i] = rand() % (101);
        }
    }
    
    
    void sort (seq_t sequence, int size) {
        for (int i = 0; i < (size - 1); i++) {
            for (int j = 0; j < (size - i - 1); j++) {
                if (sequence[j] > sequence[j+1]) {
                    swap(&sequence[j], &sequence[j+1]);
                }
            }
        }
    }
    
    void swap (seq_t first, seq_t second) {
        uint32_t temp = *first;
        *first = *second;
        *second = temp;
    }

    =============== cheri.h  code below ======================================

    /*===---- cheri.h - Header for CHERI capabilities -----------------------===*\
     *
     * Copyright (c) 2014 David Chisnall
     * Copyright (c) 2018 Alex Richardson
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     *
    \*===----------------------------------------------------------------------===*/
    #ifndef _CHERI_H
    #define _CHERI_H
    
    #pragma once
    
    #ifdef __aarch64__
    typedef unsigned int cheri_perms_t;
    #else
    typedef unsigned short cheri_perms_t;
    #endif
    typedef unsigned short cheri_flags_t;
    typedef unsigned __INT32_TYPE__ cheri_type_t;
    #ifdef __cplusplus
    #define __cheri_bool bool
    #else
    #define __cheri_bool _Bool
    #endif
    
    #if __has_feature(capabilities)
    #define __IF_CAPS(x, y) x
    typedef __intcap_t intcap_t;
    typedef __uintcap_t uintcap_t;
    #ifdef WANT_CHERI_QUALIFIER_MACROS
    #define capability __capability
    #define output __cheri_output
    #define input __cheri_input
    #endif
    #else
    #define __IF_CAPS(x, y) y
    typedef __INTPTR_TYPE__ intcap_t;
    typedef __UINTPTR_TYPE__ uintcap_t;
    #define __capability
    #ifdef WANT_CHERI_QUALIFIER_MACROS
    #define capability
    #define output
    #define input
    #endif
    #endif
    
    #define __CHERI_GET(__name, __type, __get, __default)            \
      static inline __type                                                        \
      cheri_##__name##__get(void * __capability __cap)                              \
      {                                                                           \
        return __IF_CAPS(__builtin_cheri_##__name##__get(__cap), __default);     \
      }
    
    #define __CHERI_SET(__name, __type, __set)                                     \
      static inline void *__capability cheri_##__name##__set(                      \
          void *__capability __cap, __type __val) {                                \
        return __IF_CAPS(__builtin_cheri_##__name##__set(__cap, __val),            \
                         (void *)__cap);                                           \
      }
    
    #define __CHERI_ACCESSOR(__name, __type, __set, __get, __default)            \
      __CHERI_GET(__name, __type, __get, __default)                              \
      __CHERI_SET(__name, __type, __set)                                         \
    
    __CHERI_GET(length, __SIZE_TYPE__, _get, __SIZE_MAX__)
    __CHERI_GET(base, __SIZE_TYPE__, _get, __SIZE_MAX__)
    __CHERI_ACCESSOR(offset, __SIZE_TYPE__, _set, _get, __SIZE_MAX__)
    __CHERI_GET(type, cheri_type_t, _get, 0)
    __CHERI_ACCESSOR(perms, cheri_perms_t, _and, _get, 0)
    __CHERI_ACCESSOR(flags, cheri_flags_t, _set, _get, 0)
    __CHERI_GET(tag, __cheri_bool, _get, 0)
    __CHERI_GET(sealed, __cheri_bool, _get, 0)
    
    static inline
    void * __capability cheri_offset_increment(void *__capability __cap,
                                             __PTRDIFF_TYPE__ __offset) {
      return __IF_CAPS(__builtin_cheri_offset_increment(__cap, __offset),
                       ((char*)__cap) + __offset);
    }
    
    static inline
    void * __capability cheri_tag_clear(void * __capability __cap) {
      return __IF_CAPS(__builtin_cheri_tag_clear(__cap), (void*)__cap);
    }
    
    static inline
    void * __capability cheri_seal(void * __capability __cap,
                                   const void * __capability __type) {
      return __IF_CAPS(__builtin_cheri_seal(__cap, __type), (void*)__cap);
    }
    
    static inline
    void * __capability cheri_unseal(void * __capability __cap,
                                     const void * __capability __type) {
      return __IF_CAPS(__builtin_cheri_unseal(__cap, __type), (void*)__cap);
    }
    
    static inline
    void * __capability cheri_bounds_set(void *__capability __cap,
                                       __SIZE_TYPE__ __bounds) {
      return __IF_CAPS(__builtin_cheri_bounds_set(__cap, __bounds), (void*)__cap);
    }
    
    static inline
    __SIZE_TYPE__ cheri_round_representable_length(__SIZE_TYPE__ __length) {
      return __IF_CAPS(__builtin_cheri_round_representable_length(__length), __length);
    }
    
    static inline
    __SIZE_TYPE__ cheri_round_representable_mask(__SIZE_TYPE__ __mask) {
      return __IF_CAPS(__builtin_cheri_representable_alignment_mask(__mask), __mask);
    }
    
    static inline
    __SIZE_TYPE__ cheri_copy_from_high(void *__capability __cap) {
      return __IF_CAPS(__builtin_cheri_copy_from_high(__cap), __SIZE_MAX__);
    }
    
    static inline
    void * __capability
    cheri_copy_to_high(const void *__capability __cap, __SIZE_TYPE__ __high) {
      return __IF_CAPS(__builtin_cheri_copy_to_high(__cap, __high), (void*)__cap);
    }
    
    static inline __SIZE_TYPE__ cheri_equal_exact(const void * __capability __cap_a,
        const void * __capability __cap_b) {
      return __IF_CAPS(__builtin_cheri_equal_exact(__cap_a, __cap_b), 0);
    }
    
    static inline __SIZE_TYPE__ cheri_subset_test(const void * __capability __cap_a,
        const void * __capability __cap_b) {
      return __IF_CAPS(__builtin_cheri_subset_test(__cap_a, __cap_b), 0);
    }
    
    #ifndef __CHERI_PURE_CAPABILITY__
    static inline
    void * __capability
    cheri_cap_from_pointer(const void * __capability __cap, void *__ptr) {
      return __IF_CAPS(__builtin_cheri_cap_from_pointer(__cap, __ptr),
                       (void *)__ptr);
    }
    
    static inline
    void * cheri_cap_to_pointer(const void * __capability __cap,
                                void * __capability __offset) {
      return __IF_CAPS(__builtin_cheri_cap_to_pointer(__cap, __offset),
                       (void *)__offset);
    }
    #endif
    
    static inline
    void cheri_perms_check(const void * __capability __cap, cheri_perms_t __perms) {
      __IF_CAPS(__builtin_cheri_perms_check(__cap, __perms), );
    }
    
    static inline
    void cheri_type_check(const void * __capability __cap,
                          const void * __capability __type) {
      __IF_CAPS(__builtin_cheri_type_check(__cap, __type), );
    }
    
    static inline
    void * __capability cheri_global_data_get(void) {
      return __IF_CAPS(__builtin_cheri_global_data_get(), 0);
    }
    
    static inline
    void * __capability cheri_program_counter_get(void) {
      return __IF_CAPS(__builtin_cheri_program_counter_get(), 0);
    }
    
    /* TODO: Should these be builtins to get better diagnostics? */
    
    static inline __attribute__((always_inline)) __attribute__((warn_unused_result))
    __PTRADDR_TYPE__
    __cheri_low_bits_get(uintcap_t ptr, __PTRADDR_TYPE__ mask) {
      /*
       * We need to return a NULL-derived capability here, so we need to explicitly
       * cast the LHS to a non-capability integer.
       */
      return (__PTRADDR_TYPE__)ptr & mask;
    }
    
    static inline __attribute__((always_inline)) __attribute__((warn_unused_result))
    uintcap_t
    __cheri_low_bits_or(uintcap_t ptr, __PTRADDR_TYPE__ bits) {
      /*
       * We want to return a LHS-derived capability here so using the default
       * uintcap_t semantics is fine.
       */
      return ptr | bits;
    }
    
    static inline __attribute__((always_inline)) __attribute__((warn_unused_result))
    uintcap_t
    __cheri_low_bits_clear(uintcap_t ptr, __PTRADDR_TYPE__ bits_mask) {
      /*
       * We want to return a LHS-derived capability here so using the default
       * uintcap_t semantics is fine.
       */
      return ptr & (~bits_mask);
    }
    
    #ifndef __cheri_usable_low_bits_mask
    #define __cheri_usable_low_bits_mask 31
    #endif
    #define __static_assert_sensible_low_bits(bits)                                \
      __extension__({                                                              \
        _Static_assert(bits < (__cheri_usable_low_bits_mask + 1),                  \
                       "Using too many low pointer bits");                         \
        _Static_assert((bits & (bits + 1)) == 0, "Mask must be all ones");         \
        (__PTRADDR_TYPE__)(bits);                                                  \
      })
    #define __runtime_assert_sensible_low_bits(bits, mask)                         \
      __extension__({                                                              \
        __PTRADDR_TYPE__ _bits = (__PTRADDR_TYPE__)(bits);                         \
        __PTRADDR_TYPE__ _mask = __static_assert_sensible_low_bits(mask);          \
        assert(((_bits & _mask) == _bits) && "Bits outside mask used!");           \
        _bits;                                                                     \
      })
    
    /*
     * Get the low bits defined in @p mask from the capability/pointer @p ptr.
     * @p mask must be a compile-time constant less than 31.
     * TODO: should we allow non-constant masks?
     *
     * @param ptr the uintptr_t that may have low bits sets
     * @param mask the mask for the low pointer bits to retrieve
     * @return a size_t containing the the low bits from @p ptr
     *
     * Rationale: this function is needed because extracting the low bits using a
     * bitwise-and operation returns a LHS-derived capability with the offset
     * field set to LHS.offset & mask. This is almost certainly not what the user
     * wanted since it will always compare not equal to any integer constant.
     * For example lots of mutex code uses something like `if ((x & 1) == 1)` to
     * detect if the lock is currently contented. This comparison always returns
     * false under CHERI the LHS of the == is a valid capability with offset 3 and
     * the RHS is an untagged intcap_t with offset 3.
     * See https://github.com/CTSRD-CHERI/clang/issues/189
     */
    #define cheri_low_bits_get(ptr, mask)                                          \
      __cheri_low_bits_get(ptr, __static_assert_sensible_low_bits(mask))
    
    /*
     * Bitwise-OR of low bits in a uintptr_t
     *
     * @param ptr the uintptr_t that may have low bits sets
     * @param bits the value to bitwise-or with @p ptr.
     * @return a uintptr_t that has the low bits  @p bits
     *
     * @note this function is not strictly required since a plain bitwise or will
     * generally give the behaviour that is expected from other platforms.
     * However, we can't really make the warning "-Wcheri-bitwise-operations"
     * trigger based on of the right hand side expression since it may not be a
     * compile-time constant.
     */
    #define cheri_low_bits_or(ptr, bits)                                           \
      __cheri_low_bits_or(ptr, __runtime_assert_sensible_low_bits(                 \
                                   bits, __cheri_usable_low_bits_mask))
    
    /*
     * Set low bits in a uintptr_t
     *
     * @param ptr the uintptr_t that may have low bits sets
     * @param mask the mask for the low pointer bits to be cleared before setting
     * them to @p bits.
     * @param bits the value to bitwise-or with @p ptr.
     * @return a uintptr_t that has the low bits defined in @p mask set to @p bits
     *
     * @note this function is not strictly required since a plain bitwise or will
     * generally give the behaviour that is expected from other platforms.
     * However, we can't really make the warning "-Wcheri-bitwise-operations"
     * trigger based on of the right hand side expression since it may not be a
     * compile-time constant.
     */
    #define cheri_low_bits_set(ptr, mask, bits)                                    \
      __cheri_low_bits_or(cheri_low_bits_clear(ptr, mask),                         \
                          __runtime_assert_sensible_low_bits(bits, mask))
    
    /*
     * Clear the bits in @p mask from the capability/pointer @p ptr. Mask must be
     * a compile-time constant less than 31
     *
     * TODO: should we allow non-constant masks?
     *
     * @param ptr the uintptr_t that may have low bits sets
     * @param mask this is the mask for the low pointer bits, not the mask for
     * the bits that should remain set.
     * @return a uintptr_t that has the low bits defined in @p mask set to zeroes
     *
     *
     */
    #define cheri_low_bits_clear(ptr, mask)                                        \
      __cheri_low_bits_clear(ptr, __static_assert_sensible_low_bits(mask))
    
    #undef __CHERI_ACCESSOR
    #undef __CHERI_GET
    #undef __CHERI_SET
    #undef __cheri_bool
    #undef __IF_CAPS
    
    #endif /* _CHERI_H */

Reply
  • Hello,

    I am trying to compile (using llvm release 1.6 for baremetal) a standalone bare-metal program of the bubblesort as shown before, and not using CHERIBSD in purecap mode. However, I am getting the same error with target and souce must be a capability:

    bubblesort_cam.c:123:37: error: invalid target type 'uint32_t *' (aka 'unsigned int *') for __cheri_tocap: target must be a capability
        seq_t sequence = (__cheri_tocap seq_t)malloc(sizeof(uint32_t) * SEQ_LEN);
                                        ^
    bubblesort_cam.c:106:15: note: expanded from macro 'seq_t'
    #define seq_t uint32_t*__capability
                  ^
    bubblesort_cam.c:135:33: error: invalid source type 'uint32_t *' (aka 'unsigned int *') for __cheri_fromcap: source must be a capability
        free((__cheri_fromcap void*)sequence);

    I am using the linker script from the one in the below link:

    git.morello-project.org/.../standalone-baremetal-readme.rst

    N.B: Since it is a standalone baremetal program I already commented out the print statements and I have enclosed the cheri.h file code below. This header file is already provided in the sample example of ARM MORELLO.

    ============bubblesort.c   code below====================================

    //==========bubblesort=============
    
    #include <stdio.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <time.h>
    #include "cheri.h"
    
    
    #define seq_t uint32_t*__capability
    
    // The __capability qualifier here is not necessary when compiling for "pure" mode
    // (because all pointers have capabilities in "pure" mode), but might be needed
    // if compiling for "hybrid" mode, so has been left in for convenience and clarity.
    
    #define SEQ_LEN 15
    
    void populate (seq_t __cheri_output sequence, int size);
    void sort (seq_t sequence, int size);
    void swap (seq_t first, seq_t second);
    
    
    int main (void) {
        //printf("Morello bare-metal bubble sort example\n\n");
    
        seq_t sequence = (__cheri_tocap seq_t)malloc(sizeof(uint32_t) * SEQ_LEN);
    
        populate(sequence, SEQ_LEN);
    
        //printf("Original sequence:\n  ");
        //print(sequence, SEQ_LEN);
    
        sort(sequence, SEQ_LEN);
    
        //printf("Sorted sequence:\n  ");
        //print(sequence, SEQ_LEN);
    
        free((__cheri_fromcap void*)sequence);
    
        return 0;
    }
    
    void populate (seq_t __cheri_output sequence, int size) {
        srand(time(NULL));
    
        for (int i = 0; i < size; i++) {
            sequence[i] = rand() % (101);
        }
    }
    
    
    void sort (seq_t sequence, int size) {
        for (int i = 0; i < (size - 1); i++) {
            for (int j = 0; j < (size - i - 1); j++) {
                if (sequence[j] > sequence[j+1]) {
                    swap(&sequence[j], &sequence[j+1]);
                }
            }
        }
    }
    
    void swap (seq_t first, seq_t second) {
        uint32_t temp = *first;
        *first = *second;
        *second = temp;
    }

    =============== cheri.h  code below ======================================

    /*===---- cheri.h - Header for CHERI capabilities -----------------------===*\
     *
     * Copyright (c) 2014 David Chisnall
     * Copyright (c) 2018 Alex Richardson
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     *
    \*===----------------------------------------------------------------------===*/
    #ifndef _CHERI_H
    #define _CHERI_H
    
    #pragma once
    
    #ifdef __aarch64__
    typedef unsigned int cheri_perms_t;
    #else
    typedef unsigned short cheri_perms_t;
    #endif
    typedef unsigned short cheri_flags_t;
    typedef unsigned __INT32_TYPE__ cheri_type_t;
    #ifdef __cplusplus
    #define __cheri_bool bool
    #else
    #define __cheri_bool _Bool
    #endif
    
    #if __has_feature(capabilities)
    #define __IF_CAPS(x, y) x
    typedef __intcap_t intcap_t;
    typedef __uintcap_t uintcap_t;
    #ifdef WANT_CHERI_QUALIFIER_MACROS
    #define capability __capability
    #define output __cheri_output
    #define input __cheri_input
    #endif
    #else
    #define __IF_CAPS(x, y) y
    typedef __INTPTR_TYPE__ intcap_t;
    typedef __UINTPTR_TYPE__ uintcap_t;
    #define __capability
    #ifdef WANT_CHERI_QUALIFIER_MACROS
    #define capability
    #define output
    #define input
    #endif
    #endif
    
    #define __CHERI_GET(__name, __type, __get, __default)            \
      static inline __type                                                        \
      cheri_##__name##__get(void * __capability __cap)                              \
      {                                                                           \
        return __IF_CAPS(__builtin_cheri_##__name##__get(__cap), __default);     \
      }
    
    #define __CHERI_SET(__name, __type, __set)                                     \
      static inline void *__capability cheri_##__name##__set(                      \
          void *__capability __cap, __type __val) {                                \
        return __IF_CAPS(__builtin_cheri_##__name##__set(__cap, __val),            \
                         (void *)__cap);                                           \
      }
    
    #define __CHERI_ACCESSOR(__name, __type, __set, __get, __default)            \
      __CHERI_GET(__name, __type, __get, __default)                              \
      __CHERI_SET(__name, __type, __set)                                         \
    
    __CHERI_GET(length, __SIZE_TYPE__, _get, __SIZE_MAX__)
    __CHERI_GET(base, __SIZE_TYPE__, _get, __SIZE_MAX__)
    __CHERI_ACCESSOR(offset, __SIZE_TYPE__, _set, _get, __SIZE_MAX__)
    __CHERI_GET(type, cheri_type_t, _get, 0)
    __CHERI_ACCESSOR(perms, cheri_perms_t, _and, _get, 0)
    __CHERI_ACCESSOR(flags, cheri_flags_t, _set, _get, 0)
    __CHERI_GET(tag, __cheri_bool, _get, 0)
    __CHERI_GET(sealed, __cheri_bool, _get, 0)
    
    static inline
    void * __capability cheri_offset_increment(void *__capability __cap,
                                             __PTRDIFF_TYPE__ __offset) {
      return __IF_CAPS(__builtin_cheri_offset_increment(__cap, __offset),
                       ((char*)__cap) + __offset);
    }
    
    static inline
    void * __capability cheri_tag_clear(void * __capability __cap) {
      return __IF_CAPS(__builtin_cheri_tag_clear(__cap), (void*)__cap);
    }
    
    static inline
    void * __capability cheri_seal(void * __capability __cap,
                                   const void * __capability __type) {
      return __IF_CAPS(__builtin_cheri_seal(__cap, __type), (void*)__cap);
    }
    
    static inline
    void * __capability cheri_unseal(void * __capability __cap,
                                     const void * __capability __type) {
      return __IF_CAPS(__builtin_cheri_unseal(__cap, __type), (void*)__cap);
    }
    
    static inline
    void * __capability cheri_bounds_set(void *__capability __cap,
                                       __SIZE_TYPE__ __bounds) {
      return __IF_CAPS(__builtin_cheri_bounds_set(__cap, __bounds), (void*)__cap);
    }
    
    static inline
    __SIZE_TYPE__ cheri_round_representable_length(__SIZE_TYPE__ __length) {
      return __IF_CAPS(__builtin_cheri_round_representable_length(__length), __length);
    }
    
    static inline
    __SIZE_TYPE__ cheri_round_representable_mask(__SIZE_TYPE__ __mask) {
      return __IF_CAPS(__builtin_cheri_representable_alignment_mask(__mask), __mask);
    }
    
    static inline
    __SIZE_TYPE__ cheri_copy_from_high(void *__capability __cap) {
      return __IF_CAPS(__builtin_cheri_copy_from_high(__cap), __SIZE_MAX__);
    }
    
    static inline
    void * __capability
    cheri_copy_to_high(const void *__capability __cap, __SIZE_TYPE__ __high) {
      return __IF_CAPS(__builtin_cheri_copy_to_high(__cap, __high), (void*)__cap);
    }
    
    static inline __SIZE_TYPE__ cheri_equal_exact(const void * __capability __cap_a,
        const void * __capability __cap_b) {
      return __IF_CAPS(__builtin_cheri_equal_exact(__cap_a, __cap_b), 0);
    }
    
    static inline __SIZE_TYPE__ cheri_subset_test(const void * __capability __cap_a,
        const void * __capability __cap_b) {
      return __IF_CAPS(__builtin_cheri_subset_test(__cap_a, __cap_b), 0);
    }
    
    #ifndef __CHERI_PURE_CAPABILITY__
    static inline
    void * __capability
    cheri_cap_from_pointer(const void * __capability __cap, void *__ptr) {
      return __IF_CAPS(__builtin_cheri_cap_from_pointer(__cap, __ptr),
                       (void *)__ptr);
    }
    
    static inline
    void * cheri_cap_to_pointer(const void * __capability __cap,
                                void * __capability __offset) {
      return __IF_CAPS(__builtin_cheri_cap_to_pointer(__cap, __offset),
                       (void *)__offset);
    }
    #endif
    
    static inline
    void cheri_perms_check(const void * __capability __cap, cheri_perms_t __perms) {
      __IF_CAPS(__builtin_cheri_perms_check(__cap, __perms), );
    }
    
    static inline
    void cheri_type_check(const void * __capability __cap,
                          const void * __capability __type) {
      __IF_CAPS(__builtin_cheri_type_check(__cap, __type), );
    }
    
    static inline
    void * __capability cheri_global_data_get(void) {
      return __IF_CAPS(__builtin_cheri_global_data_get(), 0);
    }
    
    static inline
    void * __capability cheri_program_counter_get(void) {
      return __IF_CAPS(__builtin_cheri_program_counter_get(), 0);
    }
    
    /* TODO: Should these be builtins to get better diagnostics? */
    
    static inline __attribute__((always_inline)) __attribute__((warn_unused_result))
    __PTRADDR_TYPE__
    __cheri_low_bits_get(uintcap_t ptr, __PTRADDR_TYPE__ mask) {
      /*
       * We need to return a NULL-derived capability here, so we need to explicitly
       * cast the LHS to a non-capability integer.
       */
      return (__PTRADDR_TYPE__)ptr & mask;
    }
    
    static inline __attribute__((always_inline)) __attribute__((warn_unused_result))
    uintcap_t
    __cheri_low_bits_or(uintcap_t ptr, __PTRADDR_TYPE__ bits) {
      /*
       * We want to return a LHS-derived capability here so using the default
       * uintcap_t semantics is fine.
       */
      return ptr | bits;
    }
    
    static inline __attribute__((always_inline)) __attribute__((warn_unused_result))
    uintcap_t
    __cheri_low_bits_clear(uintcap_t ptr, __PTRADDR_TYPE__ bits_mask) {
      /*
       * We want to return a LHS-derived capability here so using the default
       * uintcap_t semantics is fine.
       */
      return ptr & (~bits_mask);
    }
    
    #ifndef __cheri_usable_low_bits_mask
    #define __cheri_usable_low_bits_mask 31
    #endif
    #define __static_assert_sensible_low_bits(bits)                                \
      __extension__({                                                              \
        _Static_assert(bits < (__cheri_usable_low_bits_mask + 1),                  \
                       "Using too many low pointer bits");                         \
        _Static_assert((bits & (bits + 1)) == 0, "Mask must be all ones");         \
        (__PTRADDR_TYPE__)(bits);                                                  \
      })
    #define __runtime_assert_sensible_low_bits(bits, mask)                         \
      __extension__({                                                              \
        __PTRADDR_TYPE__ _bits = (__PTRADDR_TYPE__)(bits);                         \
        __PTRADDR_TYPE__ _mask = __static_assert_sensible_low_bits(mask);          \
        assert(((_bits & _mask) == _bits) && "Bits outside mask used!");           \
        _bits;                                                                     \
      })
    
    /*
     * Get the low bits defined in @p mask from the capability/pointer @p ptr.
     * @p mask must be a compile-time constant less than 31.
     * TODO: should we allow non-constant masks?
     *
     * @param ptr the uintptr_t that may have low bits sets
     * @param mask the mask for the low pointer bits to retrieve
     * @return a size_t containing the the low bits from @p ptr
     *
     * Rationale: this function is needed because extracting the low bits using a
     * bitwise-and operation returns a LHS-derived capability with the offset
     * field set to LHS.offset & mask. This is almost certainly not what the user
     * wanted since it will always compare not equal to any integer constant.
     * For example lots of mutex code uses something like `if ((x & 1) == 1)` to
     * detect if the lock is currently contented. This comparison always returns
     * false under CHERI the LHS of the == is a valid capability with offset 3 and
     * the RHS is an untagged intcap_t with offset 3.
     * See https://github.com/CTSRD-CHERI/clang/issues/189
     */
    #define cheri_low_bits_get(ptr, mask)                                          \
      __cheri_low_bits_get(ptr, __static_assert_sensible_low_bits(mask))
    
    /*
     * Bitwise-OR of low bits in a uintptr_t
     *
     * @param ptr the uintptr_t that may have low bits sets
     * @param bits the value to bitwise-or with @p ptr.
     * @return a uintptr_t that has the low bits  @p bits
     *
     * @note this function is not strictly required since a plain bitwise or will
     * generally give the behaviour that is expected from other platforms.
     * However, we can't really make the warning "-Wcheri-bitwise-operations"
     * trigger based on of the right hand side expression since it may not be a
     * compile-time constant.
     */
    #define cheri_low_bits_or(ptr, bits)                                           \
      __cheri_low_bits_or(ptr, __runtime_assert_sensible_low_bits(                 \
                                   bits, __cheri_usable_low_bits_mask))
    
    /*
     * Set low bits in a uintptr_t
     *
     * @param ptr the uintptr_t that may have low bits sets
     * @param mask the mask for the low pointer bits to be cleared before setting
     * them to @p bits.
     * @param bits the value to bitwise-or with @p ptr.
     * @return a uintptr_t that has the low bits defined in @p mask set to @p bits
     *
     * @note this function is not strictly required since a plain bitwise or will
     * generally give the behaviour that is expected from other platforms.
     * However, we can't really make the warning "-Wcheri-bitwise-operations"
     * trigger based on of the right hand side expression since it may not be a
     * compile-time constant.
     */
    #define cheri_low_bits_set(ptr, mask, bits)                                    \
      __cheri_low_bits_or(cheri_low_bits_clear(ptr, mask),                         \
                          __runtime_assert_sensible_low_bits(bits, mask))
    
    /*
     * Clear the bits in @p mask from the capability/pointer @p ptr. Mask must be
     * a compile-time constant less than 31
     *
     * TODO: should we allow non-constant masks?
     *
     * @param ptr the uintptr_t that may have low bits sets
     * @param mask this is the mask for the low pointer bits, not the mask for
     * the bits that should remain set.
     * @return a uintptr_t that has the low bits defined in @p mask set to zeroes
     *
     *
     */
    #define cheri_low_bits_clear(ptr, mask)                                        \
      __cheri_low_bits_clear(ptr, __static_assert_sensible_low_bits(mask))
    
    #undef __CHERI_ACCESSOR
    #undef __CHERI_GET
    #undef __CHERI_SET
    #undef __cheri_bool
    #undef __IF_CAPS
    
    #endif /* _CHERI_H */

Children
  • Like before, this code builds fine on Compiler Explorer (latest Morello LLVM):

    https://cheri-compiler-explorer.cl.cam.ac.uk/z/5Ys3Pz

    I suspect you are not actually enabling Morello, causing cheri.h to #define __capability to nothing. Make sure to pass -march=morello to Clang.

  • Many thanks, Kevin, by introducing this the above error got removed however it introduced another error which failed to identify few functions as denoted by this below:

    ld.lld: error: undefined symbol: malloc
    >>> referenced by bubblesort_cam.c:123
    >>>               bubblesort_cam.o:(main)
    
    ld.lld: error: undefined symbol: time
    >>> referenced by bubblesort_cam.c:141
    >>>               bubblesort_cam.o:(main)
    >>> referenced by bubblesort_cam.c:141
    >>>               bubblesort_cam.o:(populate)
    
    ld.lld: error: undefined symbol: srand
    >>> referenced by bubblesort_cam.c:141
    >>>               bubblesort_cam.o:(main)
    >>> referenced by bubblesort_cam.c:141
    >>>               bubblesort_cam.o:(populate)
    
    ld.lld: error: undefined symbol: rand
    >>> referenced by bubblesort_cam.c:144
    >>>               bubblesort_cam.o:(main)
    >>> referenced by bubblesort_cam.c:144
    >>>               bubblesort_cam.o:(main)
    >>> referenced by bubblesort_cam.c:144
    >>>               bubblesort_cam.o:(main)
    >>> referenced 13 more times
    
    ld.lld: error: undefined symbol: free
    >>> referenced by bubblesort_cam.c:135
    >>>               bubblesort_cam.o:(main)
    

  • Sorry for the delay. It appears that the instructions do not link in libc, as LLD is directly used to link. I wonder if linking with Clang and simply specifying the base address instead of a linker script wouldn't be sufficient. That is, replace the call to ld.lld with:

    <absolute path of toolchain>/bin/clang -target aarch64-none-elf -o helloworld helloworld.o -Wl,--image-base,0xe0000000

    This links fine for me, but I haven't actually tested it. Let me know if it works for you, and if so I'll make sure to get the instructions updated.

  • Hello Kevin,

    Many thanks for the help. I have enclosed the compilation script below which I am following after making the amendments you suggested. Can you please have a look if it makes sense. However, during compilation I am getting the linking error:

    ld.lld: error: bubblesort_cam.o: cannot link object files with different EF_AARCH64_CHERI_PURECAP
    clang: error: ld.lld command failed with exit code 1 (use -v to see invocation)

    # COMPILATION SCRIPT
    
    # Script based on instructions from:
    # https://git.morello-project.org/morello/docs/-/blob/morello/release-1.6/standalone-baremetal-readme.rst 
    
    # First argument = program name (must match basename of .c file)
    
    PROGRAM_NAME=$1
    PWD=`pwd`
    
    
    
    TOOLCHAIN=/opt/llvm-project-releases-morello-baremetal-release-1.6
    
    
    ################################################
    # COMPILE PROGRAM
    
    
    
    #new technique
    
    $TOOLCHAIN/bin/clang -target aarch64-none-elf -march=morello+c64 -mabi=purecap -c $PROGRAM_NAME.c -o $PROGRAM_NAME.o -O3 -g
    $TOOLCHAIN/bin/clang -target aarch64-none-elf -o $PROGRAM_NAME $PROGRAM_NAME.o -Wl,--image-base,0xe0000000
    $TOOLCHAIN/bin/llvm-objcopy -O binary $PROGRAM_NAME.elf $PROGRAM_NAME
    
    
    
    
    ################################################
    # OUTPUT OBJDUMP (disassembly)
    
    $TOOLCHAIN/bin/llvm-objdump -sSD $PROGRAM_NAME.elf > $PROGRAM_NAME.objdump

  • Hi Sanu, almost there :) Your example is not purecap, it is hybrid, since you use capabilities explicitly. You should keep just -march=morello (and no -mabi) in the compiler flags, like before.

  • Many thanks, Kevin for helping me to reach almost the end I believe. It compiled and created the object file in line number 23 and 24 of the compilation script. However, at line 25 I think it's not able to generate and hence identify the corresponding elf and hence it is throwing the error shown below: I have enclosed the compilation script also.

    /opt/llvm-project-releases-morello-baremetal-release-1.6/bin/llvm-objcopy: error: 'bubblesort.elf': No such file or directory

    # COMPILATION SCRIPT
    
    # Script based on instructions from:
    # https://git.morello-project.org/morello/docs/-/blob/morello/release-1.6/standalone-baremetal-readme.rst 
    
    # First argument = program name (must match basename of .c file)
    
    PROGRAM_NAME=$1
    PWD=`pwd`
    
    
    
    TOOLCHAIN=/opt/llvm-project-releases-morello-baremetal-release-1.6
    
    
    ################################################
    # COMPILE PROGRAM
    
    
    
    #new technique
    
    $TOOLCHAIN/bin/clang -target aarch64-none-elf -march=morello -c $PROGRAM_NAME.c -o $PROGRAM_NAME.o -O3 -g
    $TOOLCHAIN/bin/clang -target aarch64-none-elf -o $PROGRAM_NAME $PROGRAM_NAME.o -Wl,--image-base,0xe0000000
    $TOOLCHAIN/bin/llvm-objcopy -O binary $PROGRAM_NAME.elf $PROGRAM_NAME
    
    #
    #

  • llvm-objcopy takes the input as first argument, and optionally the output as second argument (see the man page). Looks like they're swapped.

  • Many thanks, Kevin. What I noticed is that in line number 24 as compared to my previous code instead of $PROGRAM_NAME, if I replace it with $PROGRAM_NAME.elf after -o, there itself the elf is getting generated. However, is there are any need to run line 25 to generate the elf then..with the llvm-objcopy? Or what is the purpose of executing line 25 please?

    # COMPILATION SCRIPT
    
    # Script based on instructions from:
    # https://git.morello-project.org/morello/docs/-/blob/morello/release-1.6/standalone-baremetal-readme.rst 
    
    # First argument = program name (must match basename of .c file)
    
    PROGRAM_NAME=$1
    PWD=`pwd`
    
    
    
    TOOLCHAIN=/opt/llvm-project-releases-morello-baremetal-release-1.6
    
    
    ################################################
    # COMPILE PROGRAM
    
    
    
    #new technique
    
    $TOOLCHAIN/bin/clang -target aarch64-none-elf -march=morello -c $PROGRAM_NAME.c -o $PROGRAM_NAME.o -O3 -g
    $TOOLCHAIN/bin/clang -target aarch64-none-elf -o $PROGRAM_NAME.elf $PROGRAM_NAME.o -Wl,--image-base,0xe0000000
    #$TOOLCHAIN/bin/llvm-objcopy -O binary $PROGRAM_NAME.elf $PROGRAM_NAME
    
    #
    #

  • Your new version is correct. Using llvm-objcopy is required to generate a raw binary that can be used as non-secure payload, as suggested in the instructions. You cannot directly use an ELF executable as payload.

  • Many thanks, Kevin for the information. Once I apply the script to generate the elf as shown in line no 25 (script shown below), the elf is generating but I am not sure once I try to view the elf file by right-clicking and viewing through the elf content editor it displays that it is not a valid elf file.

    # COMPILATION SCRIPT
    
    # Script based on instructions from:
    # https://git.morello-project.org/morello/docs/-/blob/morello/release-1.6/standalone-baremetal-readme.rst 
    
    # First argument = program name (must match basename of .c file)
    
    PROGRAM_NAME=$1
    PWD=`pwd`
    
    
    
    TOOLCHAIN=/opt/llvm-project-releases-morello-baremetal-release-1.6
    
    
    ################################################
    # COMPILE PROGRAM
    
    
    
    #new technique
    
    $TOOLCHAIN/bin/clang -target aarch64-none-elf -march=morello -c $PROGRAM_NAME.c -o $PROGRAM_NAME.o -O3 -g
    $TOOLCHAIN/bin/clang -target aarch64-none-elf -o $PROGRAM_NAME $PROGRAM_NAME.o -Wl,--image-base,0xe0000000
    $TOOLCHAIN/bin/llvm-objcopy -O binary $PROGRAM_NAME $PROGRAM_NAME.elf
    
    #
    #

  • ok so is this version correct? changed line 24 with $PROGRAM_NAME.elf after -o and in line 25 used $PROGRAM_NAME.elf as first argument instead of the second as shown below.

    _

    # COMPILATION SCRIPT
    
    # Script based on instructions from:
    # https://git.morello-project.org/morello/docs/-/blob/morello/release-1.6/standalone-baremetal-readme.rst 
    
    # First argument = program name (must match basename of .c file)
    
    PROGRAM_NAME=$1
    PWD=`pwd`
    
    
    
    TOOLCHAIN=/opt/llvm-project-releases-morello-baremetal-release-1.6
    
    
    ################################################
    # COMPILE PROGRAM
    
    
    
    #new technique
    
    $TOOLCHAIN/bin/clang -target aarch64-none-elf -march=morello -c $PROGRAM_NAME.c -o $PROGRAM_NAME.o -O3 -g
    $TOOLCHAIN/bin/clang -target aarch64-none-elf -o $PROGRAM_NAME.elf $PROGRAM_NAME.o -Wl,--image-base,0xe0000000
    $TOOLCHAIN/bin/llvm-objcopy -O binary $PROGRAM_NAME.elf $PROGRAM_NAME
    
    #
    #