Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions examples/natmod/btree/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ BERKELEY_DB_CONFIG_FILE ?= \"extmod/berkeley-db/berkeley_db_config_port.h\"
CFLAGS += -I$(BTREE_DIR)/include
CFLAGS += -DBERKELEY_DB_CONFIG_FILE=$(BERKELEY_DB_CONFIG_FILE)
CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter
CFLAGS += -Wno-deprecated-non-prototype

SRC += $(addprefix $(realpath $(BTREE_DIR))/,\
btree/bt_close.c \
Expand Down Expand Up @@ -44,6 +45,13 @@ ifeq ($(ARCH),armv6m)
LINK_RUNTIME = 1
endif

ifeq ($(ARCH),armv7m)
ifeq ($(findstring clang,$(shell $(CC) --version)),clang)
# Link with libclang_rt.builtins.a for division helper functions
LINK_RUNTIME = 1
endif
endif

include $(MPY_DIR)/py/dynruntime.mk

# btree needs gnu99 defined
Expand Down
17 changes: 17 additions & 0 deletions examples/natmod/btree/btree_c.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,20 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a

MP_DYNRUNTIME_INIT_EXIT
}

// On x86 and x64 (at least) Clang brings in its own memset() implementation,
// which will check at runtime which CPU features are available and then pick
// the fastest implementation depending on the running environment.
//
// This unfortunately includes a series of dependencies that do have a
// non-empty data section, which is currently not supported. Therefore if we
// detect Clang we provide our own naïve memset implementation.

#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
__attribute__((weak)) void *memset(void *pointer, int character, size_t length) {
for (size_t index = 0; index < length; ++index) {
((char *)pointer)[index] = (char)character;
}
return pointer;
}
#endif
9 changes: 8 additions & 1 deletion examples/natmod/deflate/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,15 @@ SRC = deflate.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc)
ARCH ?= x64

ifeq ($(ARCH),armv7m)
ifeq ($(findstring clang,$(shell $(CC) --version)),clang)
# Link with libclang_rt.a for memset
LINK_RUNTIME = 1
endif
endif

ifeq ($(ARCH),armv6m)
# Link with libgcc.a for division helper functions
# Link with libgcc.a or libclang_rt.a for division helper functions
LINK_RUNTIME = 1
endif

Expand Down
17 changes: 17 additions & 0 deletions examples/natmod/deflate/deflate.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,20 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a

MP_DYNRUNTIME_INIT_EXIT
}

// On x86 and x64 (at least) Clang brings in its own memset() implementation,
// which will check at runtime which CPU features are available and then pick
// the fastest implementation depending on the running environment.
//
// This unfortunately includes a series of dependencies that do have a
// non-empty data section, which is currently not supported. Therefore if we
// detect Clang we provide our own naïve memset implementation.

#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
__attribute__((weak)) void *memset(void *pointer, int character, size_t length) {
for (size_t index = 0; index < length; ++index) {
((char *)pointer)[index] = (char)character;
}
return pointer;
}
#endif
7 changes: 7 additions & 0 deletions examples/natmod/features2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ SRC = main.c prod.c test.py
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc)
ARCH = x64

ifeq ($(findstring clang,$(shell $(CC) --version)),clang)
ifeq ($(ARCH),$(filter $(ARCH),armv6m armv7m rv32imc))
# Link with both libc.a and libclang_rt.builtins.a
LINK_CLANG_LIBC = 1
endif
endif

# Link with libm.a and libgcc.a from the toolchain
LINK_RUNTIME = 1

Expand Down
6 changes: 6 additions & 0 deletions examples/natmod/framebuf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ SRC = framebuf.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc)
ARCH ?= x64

ifeq ($(ARCH),armv7m)
ifeq ($(findstring clang,$(shell $(CC) --version)),clang)
LINK_RUNTIME = 1
endif
endif

ifeq ($(ARCH),armv6m)
# Link with libgcc.a for division helper functions
LINK_RUNTIME = 1
Expand Down
17 changes: 17 additions & 0 deletions examples/natmod/framebuf/framebuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,20 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a

MP_DYNRUNTIME_INIT_EXIT
}

// On x86 and x64 (at least) Clang brings in its own memset() implementation,
// which will check at runtime which CPU features are available and then pick
// the fastest implementation depending on the running environment.
//
// This unfortunately includes a series of dependencies that do have a
// non-empty data section, which is currently not supported. Therefore if we
// detect Clang we provide our own naïve memset implementation.

#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
__attribute__((weak)) void *memset(void *pointer, int character, size_t length) {
for (size_t index = 0; index < length; ++index) {
((char *)pointer)[index] = (char)character;
}
return pointer;
}
#endif
7 changes: 7 additions & 0 deletions examples/natmod/re/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ SRC = re.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc)
ARCH = x64

ifeq ($(ARCH),armv7m)
ifeq ($(findstring clang,$(shell $(CC) --version)),clang)
# Link with libclang_rt.a for memmove
LINK_RUNTIME = 1
endif
endif

ifeq ($(ARCH),armv6m)
# Link with libgcc.a for division helper functions
LINK_RUNTIME = 1
Expand Down
17 changes: 17 additions & 0 deletions examples/natmod/re/re.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,20 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a

MP_DYNRUNTIME_INIT_EXIT
}

// On x86 and x64 (at least) Clang brings in its own memset() implementation,
// which will check at runtime which CPU features are available and then pick
// the fastest implementation depending on the running environment.
//
// This unfortunately includes a series of dependencies that do have a
// non-empty data section, which is currently not supported. Therefore if we
// detect Clang we provide our own naïve memset implementation.

#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
__attribute__((weak)) void *memset(void *pointer, int character, size_t length) {
for (size_t index = 0; index < length; ++index) {
((char *)pointer)[index] = (char)character;
}
return pointer;
}
#endif
50 changes: 40 additions & 10 deletions py/dynruntime.mk
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# MPY_DIR must be set to the top of the MicroPython source tree

BUILD ?= build
CC := gcc

ECHO = @echo
RM = /bin/rm
Expand Down Expand Up @@ -104,13 +105,15 @@ MICROPY_FLOAT_IMPL ?= float
else ifeq ($(ARCH),rv32imc)

# rv32imc
ifneq ($(findstring clang,$(shell $(CC) --version)),clang)
CROSS = riscv64-unknown-elf-
endif
CFLAGS_ARCH += -march=rv32imac -mabi=ilp32 -mno-relax
# If Picolibc is available then select it explicitly. Ubuntu 24.04 ships its
# bare metal RISC-V toolchain with Picolibc rather than Newlib, and the default
# is "nosys" so a value must be provided. To avoid having per-distro
# workarounds, always select Picolibc if available.
PICOLIBC_SPECS := $(shell $(CROSS)gcc --print-file-name=picolibc.specs)
PICOLIBC_SPECS := $(shell $(CROSS)$(CC) --print-file-name=picolibc.specs)
ifneq ($(PICOLIBC_SPECS),picolibc.specs)
CFLAGS_ARCH += -specs=$(PICOLIBC_SPECS)
USE_PICOLIBC := 1
Expand All @@ -123,13 +126,15 @@ MICROPY_FLOAT_IMPL ?= none
else ifeq ($(ARCH),rv64imc)

# rv64imc
ifneq ($(findstring clang,$(shell $(CC) --version)),clang)
CROSS = riscv64-unknown-elf-
endif
CFLAGS_ARCH += -march=rv64imac -mabi=lp64 -mno-relax
# If Picolibc is available then select it explicitly. Ubuntu 24.04 ships its
# bare metal RISC-V toolchain with Picolibc rather than Newlib, and the default
# is "nosys" so a value must be provided. To avoid having per-distro
# workarounds, always select Picolibc if available.
PICOLIBC_SPECS := $(shell $(CROSS)gcc --print-file-name=picolibc.specs)
PICOLIBC_SPECS := $(shell $(CROSS)$(CC) --print-file-name=picolibc.specs)
ifneq ($(PICOLIBC_SPECS),picolibc.specs)
CFLAGS_ARCH += -specs=$(PICOLIBC_SPECS)
USE_PICOLIBC := 1
Expand All @@ -143,12 +148,17 @@ else
$(error architecture '$(ARCH)' not supported)
endif

ifneq ($(findstring -musl,$(shell $(CROSS)gcc -dumpmachine)),)
ifeq ($(findstring clang,$(shell $(CC) --version)),clang)
CROSS =
endif

ifneq ($(findstring -musl,$(shell $(CROSS)$(CC) -dumpmachine)),)
USE_MUSL := 1
endif

MICROPY_FLOAT_IMPL_UPPER = $(shell echo $(MICROPY_FLOAT_IMPL) | tr '[:lower:]' '[:upper:]')
CFLAGS += $(CFLAGS_ARCH) -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_$(MICROPY_FLOAT_IMPL_UPPER)
CFLAGS += $(CFLAGS_EXTRA)

ifeq ($(LINK_RUNTIME),1)
# All of these picolibc-specific directives are here to work around a
Expand All @@ -175,8 +185,21 @@ LIBM_NAME := libc.a
else
LIBM_NAME := libm.a
endif
LIBGCC_PATH := $(realpath $(shell $(CROSS)gcc $(CFLAGS) --print-libgcc-file-name))
LIBM_PATH := $(realpath $(shell $(CROSS)gcc $(CFLAGS) --print-file-name=$(LIBM_NAME)))
# Clang will output the path to libclang_rt.builtins.a instead. The problem is
# that some symbols are duplicated between the builtins library and libc.a. In
# these cases let's leave it to the user to figure out how to handle this for
# the time being.
TOOLCHAIN_LIBGCC := $(realpath $(shell $(CROSS)$(CC) $(CFLAGS) --print-libgcc-file-name))
ifneq ($(findstring clang,$(shell $(CC) --version)),clang)
LIBGCC_PATH = $(TOOLCHAIN_LIBGCC)
else
ifneq ($(LINK_CLANG_CLANGRT),0)
LIBGCC_PATH = $(TOOLCHAIN_LIBGCC)
else
LIBGCC_PATH =
endif
endif
LIBM_PATH := $(realpath $(shell $(CROSS)$(CC) $(CFLAGS) --print-file-name=$(LIBM_NAME)))
ifeq ($(USE_PICOLIBC),1)
ifeq ($(LIBM_PATH),)
# The CROSS toolchain prefix usually ends with a dash, but that may not be
Expand All @@ -189,7 +212,16 @@ PICOLIBC_ROOT ?= /usr/lib/picolibc/$(CROSS_PREFIX)/lib
LIBM_PATH := $(PICOLIBC_ROOT)/$(PICOLIBC_ARCH)/$(PICOLIBC_ABI)/$(LIBM_NAME)
endif
endif
MPY_LD_FLAGS += $(addprefix -l, $(LIBGCC_PATH) $(LIBM_PATH))
ifneq ($(LINK_CLANG_LIBC),)
ifeq ($(findstring clang,$(shell $(CC) --version)),clang)
LIBC_PATH := $(realpath $(shell $(CROSS)$(CC) $(CFLAGS) --print-file-name=libc.a))
else
LIBC_PATH =
endif
else
LIBC_PATH =
endif
MPY_LD_FLAGS += $(addprefix -l, $(LIBGCC_PATH) $(LIBM_PATH) $(LIBC_PATH))
endif
ifneq ($(MPY_EXTERN_SYM_FILE),)
MPY_LD_FLAGS += --externs "$(realpath $(MPY_EXTERN_SYM_FILE))"
Expand All @@ -198,8 +230,6 @@ ifneq ($(ARCH_FLAGS),)
MPY_LD_FLAGS += --arch-flags "$(ARCH_FLAGS)"
endif

CFLAGS += $(CFLAGS_EXTRA)

################################################################################
# Build rules

Expand All @@ -224,12 +254,12 @@ $(CONFIG_H): $(SRC)
# Build .o from .c source files
$(BUILD)/%.o: %.c $(CONFIG_H) Makefile
$(ECHO) "CC $<"
$(Q)$(CROSS)gcc $(CFLAGS) -o $@ -c $<
$(Q)$(CROSS)$(CC) $(CFLAGS) -o $@ -c $<

# Build .o from .S source files
$(BUILD)/%.o: %.S $(CONFIG_H) Makefile
$(ECHO) "AS $<"
$(Q)$(CROSS)gcc $(CFLAGS) -o $@ -c $<
$(Q)$(CROSS)$(CC) $(CFLAGS) -o $@ -c $<

# Build .mpy from .py source files
$(BUILD)/%.mpy: %.py
Expand Down
4 changes: 4 additions & 0 deletions py/mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,18 @@
#endif

#if MP_INT_TYPE == MP_INT_TYPE_INTPTR
#if !defined(MP_INT_TYPES_DEFINED)
typedef intptr_t mp_int_t;
typedef uintptr_t mp_uint_t;
#endif
#define MP_INT_MAX INTPTR_MAX
#define MP_INT_MIN INTPTR_MIN
#define MP_UINT_MAX INTPTR_UMAX
#elif MP_INT_TYPE == MP_INT_TYPE_INT64
#if !defined(MP_INT_TYPES_DEFINED)
typedef int64_t mp_int_t;
typedef uint64_t mp_uint_t;
#endif
#define MP_INT_MAX INT64_MAX
#define MP_INT_MIN INT64_MIN
#define MP_UINT_MAX INT64_UMAX
Expand Down
29 changes: 19 additions & 10 deletions tools/mpy_ld.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
R_RISCV_TLSDESC_LOAD_LO12 = 63
R_RISCV_TLSDESC_ADD_LO12 = 64
R_RISCV_TLSDESC_CALL = 65
R_ARM_GOT_PREL = 96

################################################################################
# Architecture configuration
Expand Down Expand Up @@ -225,10 +226,13 @@ def __init__(
self.qstr_entry_size = 2
self.word_size = word_size
self.arch_got = arch_got
self.asm_jump = asm_jump
self._asm_jump = asm_jump
self.separate_rodata = separate_rodata
self.delayed_entry_offset = delayed_entry_offset

def asm_jump(self, target):
return b"" if target == 0 else self._asm_jump(target)


ARCH_DATA = {
"x86": ArchData(
Expand All @@ -249,28 +253,28 @@ def __init__(
"EM_ARM",
MP_NATIVE_ARCH_ARMV6M << 2,
4,
(R_ARM_GOT_BREL,),
(R_ARM_GOT_BREL, R_ARM_GOT_PREL),
asm_jump_thumb,
),
"armv7m": ArchData(
"EM_ARM",
MP_NATIVE_ARCH_ARMV7M << 2,
4,
(R_ARM_GOT_BREL,),
(R_ARM_GOT_BREL, R_ARM_GOT_PREL),
asm_jump_thumb2,
),
"armv7emsp": ArchData(
"EM_ARM",
MP_NATIVE_ARCH_ARMV7EMSP << 2,
4,
(R_ARM_GOT_BREL,),
(R_ARM_GOT_BREL, R_ARM_GOT_PREL),
asm_jump_thumb2,
),
"armv7emdp": ArchData(
"EM_ARM",
MP_NATIVE_ARCH_ARMV7EMDP << 2,
4,
(R_ARM_GOT_BREL,),
(R_ARM_GOT_BREL, R_ARM_GOT_PREL),
asm_jump_thumb2,
),
"xtensa": ArchData(
Expand Down Expand Up @@ -680,10 +684,14 @@ def do_relocation_text(env, text_addr, r):
# Relcation pointing to GOT
reloc = addr = env.got_entries[s.name].offset

elif env.arch.name == "EM_X86_64" and r_info_type in (
R_X86_64_GOTPCREL,
R_X86_64_REX_GOTPCRELX,
):
elif (
env.arch.name == "EM_X86_64"
and r_info_type
in (
R_X86_64_GOTPCREL,
R_X86_64_REX_GOTPCRELX,
)
) or (env.arch.name == "EM_ARM" and r_info_type == R_ARM_GOT_PREL):
# Relcation pointing to GOT
got_entry = env.got_entries[s.name]
addr = env.got_section.addr + got_entry.offset
Expand Down Expand Up @@ -1509,7 +1517,8 @@ def do_preprocess(args):
"#include <stdint.h>\n"
"typedef uintptr_t mp_uint_t;\n"
"typedef intptr_t mp_int_t;\n"
"typedef uintptr_t mp_off_t;",
"typedef uintptr_t mp_off_t;\n"
"#define MP_INT_TYPES_DEFINED",
file=f,
)
for i, q in enumerate(static_qstrs):
Expand Down
Loading