-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add LLVM libc sample #538
Add LLVM libc sample #538
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# | ||
# Copyright (c) 2020-2024, Arm Limited and affiliates. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
|
||
include ../../../Makefile.conf | ||
|
||
build: hello.elf | ||
|
||
hello.elf: *.c | ||
../$(BIN_PATH)/clang --config=llvmlibc.cfg $(MICROBIT_TARGET) -nostartfiles -lsemihost -g -fno-exceptions -fno-rtti -T microbit-llvmlibc.ld -o hello.elf $^ | ||
|
||
%.hex: %.elf | ||
../$(BIN_PATH)/llvm-objcopy -O ihex $< $@ | ||
|
||
run: hello.hex | ||
qemu-system-arm -M microbit -semihosting -nographic -device loader,file=$< | ||
|
||
debug: hello.hex | ||
qemu-system-arm -M microbit -semihosting -nographic -device loader,file=$< -s -S | ||
|
||
clean: | ||
rm -f *.elf *.hex | ||
|
||
.PHONY: clean run debug |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright (c) 2024, Arm Limited and affiliates. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
|
||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include <stddef.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <stdint.h> | ||
|
||
extern int main(int argc, char** argv); | ||
|
||
extern void _platform_init(); | ||
|
||
extern char __data_source[]; | ||
extern char __data_start[]; | ||
extern char __data_end[]; | ||
extern char __data_size[]; | ||
extern char __bss_start[]; | ||
extern char __bss_end[]; | ||
extern char __bss_size[]; | ||
extern char __tls_base[]; | ||
extern char __tdata_end[]; | ||
extern char __tls_end[]; | ||
|
||
void _start(void) { | ||
memcpy(__data_start, __data_source, (uintptr_t) __data_size); | ||
memset(__bss_start, '\0', (uintptr_t) __bss_size); | ||
_platform_init(); | ||
_Exit(main(0, NULL)); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Copyright (c) 2024, Arm Limited and affiliates. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
|
||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include <assert.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <math.h> | ||
|
||
/* Example that uses heap, string and math library */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure you have used the math library, have you? I can only see a call to The problem with the actual math.h functions in embedded LLVM libc is that they won't make a good demo, because you can't printf the floating-point results, because FP printf is left out in the embedded build profile! I suppose if you really wanted to demonstrate math.h functions, you could do something that has an integer final result, along the lines of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That will teach me for using the list of math functions in cppreference. Was trying to find one that returned an integer. I've used |
||
|
||
int main(void) { | ||
const char *hello_s = "hello "; | ||
const char *world_s = "world"; | ||
const size_t hello_s_len = strlen(hello_s); | ||
const size_t world_s_len = strlen(world_s); | ||
const size_t out_s_len = hello_s_len + world_s_len + 1; | ||
char *out_s = (char*) malloc(out_s_len); | ||
assert(out_s_len >= hello_s_len + 1); | ||
strncpy(out_s, hello_s, hello_s_len + 1); | ||
assert(out_s_len >= strlen(out_s) + world_s_len + 1); | ||
strncat(out_s, world_s, world_s_len + 1); | ||
printf("%s %d\n", out_s, abs(-3)); | ||
free(out_s); | ||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
/* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* | ||
* Copyright © 2019 Keith Packard | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to add Arm copyright as well? Presumably this was tweaked to meet the needs of the sample. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was a trivial modification, but it is probably best to add the additional copyright anyway. |
||
* Copyright (c) 2024, Arm Limited and affiliates. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions | ||
* are met: | ||
* | ||
* 1. Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* | ||
* 2. Redistributions in binary form must reproduce the above | ||
* copyright notice, this list of conditions and the following | ||
* disclaimer in the documentation and/or other materials provided | ||
* with the distribution. | ||
* | ||
* 3. Neither the name of the copyright holder nor the names of its | ||
* contributors may be used to endorse or promote products derived | ||
* from this software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | ||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
* OF THE POSSIBILITY OF SUCH DAMAGE. | ||
*/ | ||
|
||
/* Linker script adapted from picolibc linker script | ||
* llvm-libc uses different linker defined symbols for heap placement. | ||
*/ | ||
|
||
/* Hard-coded for Cortex-M0 */ | ||
MEMORY | ||
{ | ||
boot_flash (rx!w) : | ||
ORIGIN = 0x00000000, | ||
LENGTH = 0x3000 | ||
flash (rx!w) : | ||
ORIGIN = 0x3000, | ||
LENGTH = 0x3d000 | ||
ram (w!rx) : | ||
ORIGIN = 0x20000000, | ||
LENGTH = 0x4000 | ||
} | ||
|
||
PHDRS | ||
{ | ||
text_boot_flash PT_LOAD; | ||
text PT_LOAD; | ||
ram_init PT_LOAD; | ||
ram PT_LOAD; | ||
tls PT_TLS; | ||
} | ||
|
||
SECTIONS | ||
{ | ||
PROVIDE(__stack = ORIGIN(ram) + LENGTH(ram)); | ||
|
||
.boot_flash : { | ||
KEEP (*(.vectors)) | ||
} >boot_flash AT>boot_flash :text_boot_flash | ||
|
||
.text : { | ||
|
||
/* code */ | ||
*(.text.unlikely .text.unlikely.*) | ||
*(.text.startup .text.startup.*) | ||
*(.text .text.* .opd .opd.*) | ||
PROVIDE (__start___lcxx_override = .); | ||
*(__lcxx_override) | ||
PROVIDE (__stop___lcxx_override = .); | ||
*(.gnu.linkonce.t.*) | ||
KEEP (*(.fini .fini.*)) | ||
__text_end = .; | ||
|
||
PROVIDE (__etext = __text_end); | ||
PROVIDE (_etext = __text_end); | ||
PROVIDE (etext = __text_end); | ||
|
||
/* Need to pre-align so that the symbols come after padding */ | ||
. = ALIGN(8); | ||
|
||
/* lists of constructors and destructors */ | ||
PROVIDE_HIDDEN ( __preinit_array_start = . ); | ||
KEEP (*(.preinit_array)) | ||
PROVIDE_HIDDEN ( __preinit_array_end = . ); | ||
|
||
PROVIDE_HIDDEN ( __init_array_start = . ); | ||
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) | ||
KEEP (*(.init_array .ctors)) | ||
PROVIDE_HIDDEN ( __init_array_end = . ); | ||
|
||
PROVIDE_HIDDEN ( __fini_array_start = . ); | ||
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) | ||
KEEP (*(.fini_array .dtors)) | ||
PROVIDE_HIDDEN ( __fini_array_end = . ); | ||
|
||
} >flash AT>flash :text | ||
|
||
.rodata : { | ||
|
||
/* read-only data */ | ||
*(.rdata) | ||
*(.rodata .rodata.*) | ||
*(.gnu.linkonce.r.*) | ||
|
||
*(.srodata.cst16) | ||
*(.srodata.cst8) | ||
*(.srodata.cst4) | ||
*(.srodata.cst2) | ||
*(.srodata .srodata.*) | ||
|
||
} >flash AT>flash :text | ||
|
||
.data.rel.ro : { | ||
|
||
/* data that needs relocating */ | ||
*(.data.rel.ro .data.rel.ro.*) | ||
|
||
} >flash AT>flash :text | ||
|
||
|
||
/* | ||
* Needs to be in its own segment with the PLT entries first | ||
* so that the linker will compute the offsets to those | ||
* entries correctly. | ||
*/ | ||
.got : { | ||
*(.got.plt) | ||
*(.got) | ||
} >flash AT>flash :text | ||
|
||
.except_ordered : { | ||
*(.gcc_except_table *.gcc_except_table.*) | ||
*(.ARM.extab* .gnu.linkonce.armextab.*) | ||
} >flash AT>flash :text | ||
|
||
.except_unordered : { | ||
. = ALIGN(8); | ||
|
||
PROVIDE(__exidx_start = .); | ||
*(.ARM.exidx*) | ||
PROVIDE(__exidx_end = .); | ||
} >flash AT>flash :text | ||
|
||
|
||
.data : /* For ld.bfd: ALIGN_WITH_INPUT */ { | ||
*(.data .data.*) | ||
*(.gnu.linkonce.d.*) | ||
|
||
/* Need to pre-align so that the symbols come after padding */ | ||
. = ALIGN(8); | ||
|
||
PROVIDE( __global_pointer$ = . + 0x800 ); | ||
PROVIDE( _gp = . + 0x8000); | ||
*(.sdata .sdata.* .sdata2.*) | ||
*(.gnu.linkonce.s.*) | ||
} >ram AT>flash :ram_init | ||
PROVIDE(__data_start = ADDR(.data)); | ||
PROVIDE(__data_source = LOADADDR(.data)); | ||
|
||
/* Thread local initialized data. This gets | ||
* space allocated as it is expected to be placed | ||
* in ram to be used as a template for TLS data blocks | ||
* allocated at runtime. We're slightly abusing that | ||
* by placing the data in flash where it will be copied | ||
* into the allocate ram addresses by the existing | ||
* data initialization code in crt0. | ||
* BFD includes .tbss alignment when computing .tdata | ||
* alignment, but for ld.lld we have to explicitly pad | ||
* as it only guarantees usage as a TLS template works | ||
* rather than supporting this use case. | ||
*/ | ||
.tdata : ALIGN(__tls_align) /* For ld.bfd: ALIGN_WITH_INPUT */ { | ||
*(.tdata .tdata.* .gnu.linkonce.td.*) | ||
PROVIDE(__data_end = .); | ||
PROVIDE(__tdata_end = .); | ||
} >ram AT>flash :tls :ram_init | ||
PROVIDE( __tls_base = ADDR(.tdata)); | ||
PROVIDE( __tdata_start = ADDR(.tdata)); | ||
PROVIDE( __tdata_source = LOADADDR(.tdata) ); | ||
PROVIDE( __tdata_source_end = LOADADDR(.tdata) + SIZEOF(.tdata) ); | ||
PROVIDE( __data_source_end = __tdata_source_end ); | ||
PROVIDE( __tdata_size = SIZEOF(.tdata) ); | ||
|
||
PROVIDE( __edata = __data_end ); | ||
PROVIDE( _edata = __data_end ); | ||
PROVIDE( edata = __data_end ); | ||
PROVIDE( __data_size = __data_end - __data_start ); | ||
PROVIDE( __data_source_size = __data_source_end - __data_source ); | ||
|
||
.tbss (NOLOAD) : { | ||
*(.tbss .tbss.* .gnu.linkonce.tb.*) | ||
*(.tcommon) | ||
PROVIDE( __tls_end = . ); | ||
PROVIDE( __tbss_end = . ); | ||
} >ram AT>ram :tls :ram | ||
PROVIDE( __bss_start = ADDR(.tbss)); | ||
PROVIDE( __tbss_start = ADDR(.tbss)); | ||
PROVIDE( __tbss_offset = ADDR(.tbss) - ADDR(.tdata) ); | ||
PROVIDE( __tbss_size = SIZEOF(.tbss) ); | ||
PROVIDE( __tls_size = __tls_end - __tls_base ); | ||
PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); | ||
PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); | ||
PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); | ||
PROVIDE( __arm64_tls_tcb_offset = MAX(16, __tls_align) ); | ||
|
||
.bss (NOLOAD) : { | ||
*(.sbss*) | ||
*(.gnu.linkonce.sb.*) | ||
*(.bss .bss.*) | ||
*(.gnu.linkonce.b.*) | ||
*(COMMON) | ||
|
||
/* Align the heap */ | ||
. = ALIGN(8); | ||
__bss_end = .; | ||
} >ram AT>ram :ram | ||
PROVIDE( __non_tls_bss_start = ADDR(.bss) ); | ||
PROVIDE( __end = __bss_end ); | ||
_end = __bss_end; | ||
PROVIDE( end = __bss_end ); | ||
PROVIDE( __bss_size = __bss_end - __bss_start ); | ||
|
||
/* Make the rest of memory available for heap storage | ||
* LLVM libc denotes heap with [__end, __llvm_libc_heap_limit) | ||
*/ | ||
PROVIDE (__llvm_libc_heap_limit = __stack - (DEFINED(__stack_size) ? __stack_size : 4K)); | ||
} | ||
|
||
ASSERT( __data_size == __data_source_size, "ERROR: .data/.tdata flash size does not match RAM size"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pedantry: formally, memcpy and memset take a
size_t
, not auintptr_t
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks will fix.