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.
`seq_t` looks to be defined as `typedef uint32_t *seq_t` which, in the hybrid ABI, is not a capability, and so __cheri_tocap/__cheri_fromcap are telling you that you aren't casting to/from a capability respectively. If you want to use a capability you need `typedef uint32_t * __capability seq_t`.
Many thanks for your reply, however it is already defined in line highlighted with bold red as shown in the code below but still the build failed:
#include "cheri.h"#include <stdio.h>#include <stdlib.h>#include <time.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 15void populate (seq_t __cheri_output sequence, int size);void print (seq_t __cheri_input 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 print (seq_t __cheri_input sequence, int size) { for (int i = 0; i < size; i++) { if (i > 0) { printf(", "); } printf("%d", sequence[i]); } printf("\n");}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;}
Dropping the cheri.h include and adding stdint.h (for uint32_t) that code compiles just fine with the latest Morello LLVM and CheriBSD: https://cheri-compiler-explorer.cl.cam.ac.uk/z/o9rcr6 (though I would recommend a typedef rather than a #define for defining a new type)
What's in your cheri.h?
Many thanks for your reply. I'll try and update you. Can you please suggest from the list of 2 toolchains which one to use for building the project
https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
I am assuming maybe I am not using the correct compiler version.
Neither points to a Morello toolchain. There is nothing wrong with using Morello LLVM, as you currently are as I understand, otherwise there is also the Morello GNU toolchain:
developer.arm.com/.../arm-gnu-toolchain-for-morello-downloads
Many thanks Kevin. I like to point out one step where I am getting stuck is that while I am trying to download it and run on the morello board the existing elf of the bubblesort program already provided as an example, it program execution is getting stuck at the halt instruction and not proceeding further and as a result the output is not displaying.I am showing a screenshot for the same.
and under the error log these 2 messages:
Execution has stopped on HLT #0xF000, which is a "semihosting" call.For background information on semihosting, seedeveloper.arm.com/.../Using-semihosting-to-access-resources-on-the-host-computerWhen connected to a model, semihosting is automatically handled by the model.When connected to real hardware, semihosting is disabled by default in the debugger. Semihosting will be enabled in the debugger when an image is loaded that contains the special symbols __auto_semihosting or __semihosting_library_function, or if you explicitly enable semihosting using the command "set semihosting enabled on".To enable semihosting when connected to real hardware, first create a "target initialization" .ds script containing this command:set semihosting enabled onthen open the debug configuration .launch file for your board, select the Debugger tab, and add the script in the "Run target initialization debugger script" field.If required, you can also add other commands into the script to setup the stack & heap, e.g.:set semihosting heap-base 0set semihosting heap-limit 0x80800000set semihosting stack-limit 0x80800000set semihosting stack-base 0x81000000heap-base 0 means "put the heap immediately above ZI (aka .bss) data. If that doesn't work, specify an absolute address with e.g.set semihosting heap-base 0x80400000Hope this helpsStephen
yes I have added that in the initialisation.ds file with the content
set semihosting enabled onset semihosting heap-base 0x80400000set semihosting heap-limit 0x80800000set semihosting stack-limit 0x80800000set semihosting stack-base 0x81000000
but pointed it to the Run target initialization debugger script. But the issue remains. As I step through it moves into an address as shown in the disassembly. The program is running as it shows but I couldn't see the output on the console
I made a fresh post describing the problem in this link
community.arm.com/.../baremetal-program-execution-on-arm-morello-board
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 */
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.
-march=morello
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_PURECAPclang: 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 # #