tools/mpy_ld.py: Add new mpy_ld.py tool and associated build files.

This commit adds a new tool called mpy_ld.py which is essentially a linker
that builds .mpy files directly from .o files.  A new header file
(dynruntime.h) and makefile fragment (dynruntime.mk) are also included
which allow building .mpy files from C source code.  Such .mpy files can
then be dynamically imported as though they were a normal Python module,
even though they are implemented in C.

Converting .o files directly (rather than pre-linked .elf files) allows the
resulting .mpy to be more efficient because it has more control over the
relocations; for example it can skip PLT indirection.  Doing it this way
also allows supporting more architectures, such as Xtensa which has
specific needs for position-independent code and the GOT.

The tool supports targets of x86, x86-64, ARM Thumb and Xtensa (windowed
and non-windowed).  BSS, text and rodata sections are supported, with
relocations to all internal sections and symbols, as well as relocations to
some external symbols (defined by dynruntime.h), and linking of qstrs.
This commit is contained in:
Damien George
2019-08-28 17:03:08 +10:00
parent 27879844d2
commit aad79adab7
3 changed files with 1305 additions and 0 deletions

134
py/dynruntime.mk Normal file
View File

@@ -0,0 +1,134 @@
# Makefile fragment for generating native .mpy files from C source
# MPY_DIR must be set to the top of the MicroPython source tree
BUILD ?= build
ECHO = @echo
RM = /bin/rm
MKDIR = /bin/mkdir
PYTHON = python3
MPY_CROSS = $(MPY_DIR)/mpy-cross/mpy-cross
MPY_TOOL = $(PYTHON) $(MPY_DIR)/tools/mpy-tool.py
MPY_LD = $(PYTHON) $(MPY_DIR)/tools/mpy_ld.py
Q = @
ifeq ("$(origin V)", "command line")
ifeq ($(V),1)
Q =
MPY_LD += '-vvv'
endif
endif
ARCH_UPPER = $(shell echo $(ARCH) | tr '[:lower:]' '[:upper:]')
CONFIG_H = $(BUILD)/$(MOD).config.h
CFLAGS += -I. -I$(MPY_DIR)
CFLAGS += -std=c99
CFLAGS += -Os
CFLAGS += -Wall -Werror -DNDEBUG
CFLAGS += -DNO_QSTR
CFLAGS += -DMP_CONFIGFILE='<$(CONFIG_H)>'
CFLAGS += -fpic -fno-common
CFLAGS += -U _FORTIFY_SOURCE # prevent use of __*_chk libc functions
#CFLAGS += -fdata-sections -ffunction-sections
MPY_CROSS_FLAGS += -march=$(ARCH)
SRC_O += $(addprefix $(BUILD)/, $(patsubst %.c,%.o,$(filter %.c,$(SRC))))
SRC_MPY += $(addprefix $(BUILD)/, $(patsubst %.py,%.mpy,$(filter %.py,$(SRC))))
################################################################################
# Architecture configuration
ifeq ($(ARCH),x86)
# x86
CROSS =
CFLAGS += -m32 -fno-stack-protector
MPY_CROSS_FLAGS += -mcache-lookup-bc
else ifeq ($(ARCH),x64)
# x64
CROSS =
CFLAGS += -fno-stack-protector
MPY_CROSS_FLAGS += -mcache-lookup-bc
else ifeq ($(ARCH),armv7m)
# thumb
CROSS = arm-none-eabi-
CFLAGS += -mthumb -mcpu=cortex-m3
else ifeq ($(ARCH),armv7emsp)
# thumb
CROSS = arm-none-eabi-
CFLAGS += -mthumb -mcpu=cortex-m4
CFLAGS += -mfpu=fpv4-sp-d16 -mfloat-abi=hard
else ifeq ($(ARCH),armv7emdp)
# thumb
CROSS = arm-none-eabi-
CFLAGS += -mthumb -mcpu=cortex-m7
CFLAGS += -mfpu=fpv5-d16 -mfloat-abi=hard
else ifeq ($(ARCH),xtensa)
# xtensa
CROSS = xtensa-lx106-elf-
CFLAGS += -mforce-l32
else ifeq ($(ARCH),xtensawin)
# xtensawin
CROSS = xtensa-esp32-elf-
CFLAGS +=
else
$(error architecture '$(ARCH)' not supported)
endif
CFLAGS += $(CFLAGS_EXTRA)
################################################################################
# Build rules
.PHONY: all clean
all: $(MOD).mpy
clean:
$(RM) -rf $(BUILD) $(CLEAN_EXTRA)
# Create build destination directories first
BUILD_DIRS = $(sort $(dir $(CONFIG_H) $(SRC_O) $(SRC_MPY)))
$(CONFIG_H) $(SRC_O) $(SRC_MPY): | $(BUILD_DIRS)
$(BUILD_DIRS):
$(Q)$(MKDIR) -p $@
# Preprocess all source files to generate $(CONFIG_H)
$(CONFIG_H): $(SRC)
$(ECHO) "GEN $@"
$(Q)$(MPY_LD) --arch $(ARCH) --preprocess -o $@ $^
# Build .o from .c source files
$(BUILD)/%.o: %.c $(CONFIG_H) Makefile
$(ECHO) "CC $<"
$(Q)$(CROSS)gcc $(CFLAGS) -o $@ -c $<
# Build .mpy from .py source files
$(BUILD)/%.mpy: %.py
$(ECHO) "MPY $<"
$(Q)$(MPY_CROSS) $(MPY_CROSS_FLAGS) -o $@ $<
# Build native .mpy from object files
$(BUILD)/$(MOD).native.mpy: $(SRC_O)
$(ECHO) "LINK $<"
$(Q)$(MPY_LD) --arch $(ARCH) --qstrs $(CONFIG_H) -o $@ $^
# Build final .mpy from all intermediate .mpy files
$(MOD).mpy: $(BUILD)/$(MOD).native.mpy $(SRC_MPY)
$(ECHO) "GEN $@"
$(Q)$(MPY_TOOL) --merge -o $@ $^