nanohub: add c++ support
nanohub implementation is not using ARM EABI support
provided by toolchain.
To have basic c++ support (no exceptions, no RTTI)
support for dynamic construction/destruction and
global and static local constructors is required.
NOTE: global and static local destructors are not supported,
because __aeabi_atexit() is currently a stub.
This patch adds necessary support.
Bug: 31256189
Change-Id: I15ce4a064654f9fa8ca9b1b76102282c86dbc41e
Signed-off-by: Alexey Polyudov <apolyudov@google.com>
diff --git a/firmware/app/app.mk b/firmware/app/app.mk
index f2cd9db..47c8de2 100644
--- a/firmware/app/app.mk
+++ b/firmware/app/app.mk
@@ -167,24 +167,21 @@
# Linker Configuration #########################################################
-LD := $(PREFIX)ld
+LD := $(PREFIX)g++
LDFLAGS := -T $(NANOHUB_DIR)/os/platform/$(PLATFORM)/lkr/app.lkr
LDFLAGS += -nostartfiles
-LDFLAGS += --gc-sections
-LDFLAGS += -Map $(OUT)/$(BIN).map
-LDFLAGS += --cref
+LDFLAGS += -Wl,--gc-sections
+LDFLAGS += -Wl,-Map,$(OUT)/$(BIN).map
+LDFLAGS += -Wl,--cref
+STATIC_LIBS += -lgcc
ifeq ($(BIN_MODE),static)
-LDFLAGS += -static
-LDFLAGS += --emit-relocs
-LDFLAGS += -L$(wildcard $(TOOLCHAIN_DIR)/lib/gcc/arm-none-eabi/*/armv7e-m/softfp)
-STATIC_LIBS += -lgcc
+LDFLAGS += -Bstatic
+LDFLAGS += -Wl,--emit-relocs
else
-LDFLAGS += -shared
-LDFLAGS += --no-undefined
-LDFLAGS += --no-allow-shlib-undefined
-LDFLAGS += -L$(wildcard $(TOOLCHAIN_DIR)/lib/gcc/arm-none-eabi/*/armv7e-m/softfp)
-STATIC_LIBS += -lgcc
+LDFLAGS += -Bdynamic
+LDFLAGS += -Wl,--no-undefined
+LDFLAGS += -Wl,--no-allow-shlib-undefined
endif
# Build Rules ##################################################################
@@ -192,10 +189,12 @@
AS_SRCS := $(filter %.S, $(SRCS))
C_SRCS := $(filter %.c, $(SRCS))
CXX_SRCS := $(filter %.cc, $(SRCS))
+CPP_SRCS := $(filter %.cpp, $(SRCS))
OBJS := $(patsubst %.S, $(OUT)/%.o, $(AS_SRCS))
OBJS += $(patsubst %.c, $(OUT)/%.o, $(C_SRCS))
OBJS += $(patsubst %.cc, $(OUT)/%.o, $(CXX_SRCS))
+OBJS += $(patsubst %.cpp, $(OUT)/%.o, $(CPP_SRCS))
UNSIGNED_BIN := $(BIN).unsigned.napp
@@ -210,7 +209,7 @@
-m $(NANOHUB_KEY_PATH)/debug.pubkey -s $< $@
ifdef IMAGE_TARGET_OUT
$(IMAGE_TARGET_OUT): $(OUT)/$(BIN).napp
- mkdir -p $(dir $@)
+ @mkdir -p $(dir $@)
cp $< $(IMAGE_TARGET_OUT)
endif
@@ -234,7 +233,7 @@
$(OUT)/$(BIN).elf : $(OBJS)
@mkdir -p $(dir $@)
- $(LD) $(LDFLAGS) $(OBJS) $(STATIC_LIBS) -o $@
+ $(LD) $(CFLAGS) $(CXX_FLAGS) $(LDFLAGS) $(OBJS) $(STATIC_LIBS) -o $@
$(OUT)/%.o : %.S
@mkdir -p $(dir $@)
@@ -248,6 +247,10 @@
@mkdir -p $(dir $@)
$(CXX) $(CXX_CFLAGS) $(CFLAGS) -c $< -o $@
+$(OUT)/%.o : %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CXX_CFLAGS) $(CFLAGS) -c $< -o $@
+
# Automatic dependency resolution ##############################################
DEPS_AS = $(OUT)/deps_as
@@ -262,7 +265,7 @@
@mkdir -p $(dir $@)
$(CC) $(C_CFLAGS) $(CFLAGS) -MM $^ > $@
-$(DEPS_CXX) : $(CXX_SRCS)
+$(DEPS_CXX) : $(CXX_SRCS) $(CPP_SRCS)
@mkdir -p $(dir $@)
$(CXX) $(CXX_CFLAGS) $(CFLAGS) -MM $^ > $@
@@ -278,7 +281,7 @@
-include $(DEPS_C)
endif
-ifneq ($(CXX_SRCS), )
+ifneq ($(CXX_SRCS)$(CPP_SRCS),)
-include $(DEPS_CXX)
endif
diff --git a/firmware/app/chre/chre_test0.app/Makefile b/firmware/app/chre/chre_test0.app/Makefile
index af36ee0..135fe51 100644
--- a/firmware/app/chre/chre_test0.app/Makefile
+++ b/firmware/app/chre/chre_test0.app/Makefile
@@ -39,5 +39,3 @@
VARIANT := $(TARGET_PRODUCT)
include $(NANOHUB_DIR)/app/chre/chre.mk
-
-all: sync
diff --git a/firmware/app/chre/chre_test1.app/Android.mk b/firmware/app/chre/chre_test1.app/Android.mk
new file mode 100644
index 0000000..871d735
--- /dev/null
+++ b/firmware/app/chre/chre_test1.app/Android.mk
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_NANO_VARS)
+
+LOCAL_MODULE := chre_test1
+LOCAL_MODULE_TAGS := optional
+
+# Googl + T + 0x9001
+LOCAL_NANO_APP_ID := 476f6f676c549001
+LOCAL_NANO_APP_VERSION := 0
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+ libnanochre \
+
+LOCAL_STATIC_LIBRARIES := \
+ libnanolibc \
+ libnanolibm \
+
+LOCAL_SRC_FILES := \
+ main.cpp \
+
+include $(BUILD_NANOHUB_APP_EXECUTABLE)
diff --git a/firmware/app/chre/chre_test1.app/Makefile b/firmware/app/chre/chre_test1.app/Makefile
new file mode 100644
index 0000000..6e6390c
--- /dev/null
+++ b/firmware/app/chre/chre_test1.app/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# 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.
+#
+
+################################################################################
+#
+# test NanoApp Makefile
+#
+################################################################################
+
+
+SRCS := main.cpp
+BIN := chre_test1
+APP_ID := 476f6f676c549001
+APP_VERSION := 0
+
+# Nanohub relative path
+NANOHUB_DIR := ../../..
+
+# Device configuration #########################################################
+
+# select device variant for this app
+TARGET_PRODUCT ?= nucleo
+VARIANT := $(TARGET_PRODUCT)
+
+include $(NANOHUB_DIR)/app/chre/chre.mk
diff --git a/firmware/app/chre/chre_test1.app/main.cpp b/firmware/app/chre/chre_test1.app/main.cpp
new file mode 100644
index 0000000..22a33ce
--- /dev/null
+++ b/firmware/app/chre/chre_test1.app/main.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 <stdint.h>
+#include <inttypes.h>
+#include <chre.h>
+
+#define APP_LABEL "CHRE App 1: "
+
+/* chre.h does not define printf format attribute for chreLog() */
+void chreLog(enum chreLogLevel level, const char *str, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
+
+#define EVT_LOCAL_SETUP CHRE_EVENT_FIRST_USER_VALUE
+
+struct MyTimer {
+ uint32_t timerId;
+};
+
+struct ExtMsg
+{
+ uint8_t msg;
+ uint32_t val;
+} __attribute__((packed));
+
+static const uint64_t kOneSecond = UINT64_C(1000000000); // in nanoseconds
+
+static uint32_t mMyTid;
+static uint64_t mMyAppId;
+static int cnt;
+static struct MyTimer mTimer;
+
+// Default implementation for message free
+static void nanoappFreeMessage(void *msg, size_t size)
+{
+ chreHeapFree(msg);
+}
+
+bool nanoappStart(void)
+{
+ mMyAppId = chreGetAppId();
+ mMyTid = chreGetInstanceId();
+ cnt = 3;
+ chreSendEvent(EVT_LOCAL_SETUP, NULL, NULL, mMyTid);
+ chreLog(CHRE_LOG_INFO, APP_LABEL "init");
+ return true;
+}
+
+void nanoappEnd(void)
+{
+ chreLog(CHRE_LOG_INFO, APP_LABEL "terminating");
+}
+
+class A {
+ int *p;
+public:
+ A(int _x) {
+ p = new int[1];
+ if (p != nullptr)
+ *p = _x;
+ chreLog(CHRE_LOG_INFO, APP_LABEL "A::A(int): *p=%d", p != nullptr ? *p : 0);
+ }
+ ~A() {
+ chreLog(CHRE_LOG_INFO, APP_LABEL "A::~A(): *p=%d", p != nullptr ? *p : 0);
+ delete p;
+ p = nullptr;
+ }
+};
+
+static A global_with_ctor_dtor(1); // test the behavior of global static constructors/destructors
+
+void nanoappHandleEvent(uint32_t srcTid, uint16_t evtType, const void* evtData)
+{
+ static A local_static_with_ctor_dtor(2); // test the behavior of local static constructors/destructors
+
+ switch (evtType) {
+ case EVT_LOCAL_SETUP:
+ mTimer.timerId = chreTimerSet(kOneSecond, &mTimer, false);
+ chreLog(CHRE_LOG_INFO, APP_LABEL "started with tid %04" PRIX32
+ " timerid %" PRIu32
+ "\n", mMyTid, mTimer.timerId);
+ break;
+ case CHRE_EVENT_TIMER:
+ {
+ const struct MyTimer *t = (const struct MyTimer *)evtData;
+ auto extMsg = new ExtMsg;
+
+ chreLog(CHRE_LOG_INFO, APP_LABEL "received timer %" PRIu32
+ " (TIME: %" PRIu64
+ ") cnt: %d\n", t->timerId, chreGetTime(), cnt);
+ extMsg->msg = 0x01;
+ extMsg->val = cnt;
+ chreSendMessageToHost(extMsg, sizeof(*extMsg), 0, nanoappFreeMessage);
+ if (cnt-- <= 0)
+ chreTimerCancel(t->timerId);
+ break;
+ }
+ case CHRE_EVENT_MESSAGE_FROM_HOST:
+ {
+ const struct chreMessageFromHostData *msg = (const struct chreMessageFromHostData *)evtData;
+ const uint8_t *data = (const uint8_t *)msg->message;
+ const size_t size = msg->messageSize;
+ chreLog(CHRE_LOG_INFO, APP_LABEL "message=%p; code=%d; size=%zu",
+ data, (data && size) ? data[0] : 0, size);
+ break;
+ }
+ }
+}
diff --git a/firmware/app/chre/common/Android.mk b/firmware/app/chre/common/Android.mk
index f82d699..9a05b03 100644
--- a/firmware/app/chre/common/Android.mk
+++ b/firmware/app/chre/common/Android.mk
@@ -25,4 +25,6 @@
chre_app.c \
chre_app_syscalls.c \
+LOCAL_STATIC_LIBRARIES += libnanolibc
+
include $(BUILD_NANOHUB_APP_STATIC_LIBRARY)
diff --git a/firmware/app/chre/common/chre_app.c b/firmware/app/chre/common/chre_app.c
index a5b3f74..6d3e9c6 100644
--- a/firmware/app/chre/common/chre_app.c
+++ b/firmware/app/chre/common/chre_app.c
@@ -18,6 +18,7 @@
#include <seos.h>
#include <timer.h>
#include <toolchain.h>
+#include <crt_priv.h>
#include <chre.h>
@@ -27,12 +28,14 @@
static bool chreappStart(uint32_t tid)
{
+ __crt_init();
return nanoappStart();
}
static void chreappEnd(void)
{
nanoappEnd();
+ __crt_exit();
}
static void chreappHandle(uint32_t eventTypeAndTid, const void *eventData)
diff --git a/firmware/build/common_config.mk b/firmware/build/common_config.mk
index e00fb7d..b773145 100644
--- a/firmware/build/common_config.mk
+++ b/firmware/build/common_config.mk
@@ -33,12 +33,12 @@
-fstack-reuse=all \
-fvisibility=hidden \
-LOCAL_CPPFLAGS += \
- -std=c++11 \
- -fno-exceptions \
- -fno-rtti \
+LOCAL_CPPFLAGS += \
+ -std=c++11 \
+ -fno-exceptions \
+ -fno-rtti \
-LOCAL_LDFLAGS += \
+LOCAL_LDFLAGS += \
-nostartfiles \
-Wl,--gc-sections \
-Wl,--no-undefined \
diff --git a/firmware/build/nanohub_executable.mk b/firmware/build/nanohub_executable.mk
index b71f8c6..1f731c3 100644
--- a/firmware/build/nanohub_executable.mk
+++ b/firmware/build/nanohub_executable.mk
@@ -22,6 +22,7 @@
intermediates := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),AUX)
+nanohub_linked_map := $(intermediates)/LINKED/$(LOCAL_MODULE).map
nanohub_unchecked_elf := $(intermediates)/UNCHECKED/$(LOCAL_MODULE).elf
nanohub_checked_elf := $(intermediates)/CHECKED/$(LOCAL_MODULE).elf
nanohub_checked_bin := $(intermediates)/CHECKED/$(LOCAL_MODULE).bin
@@ -129,6 +130,7 @@
endif # TYPE == APP
LOCAL_CUSTOM_BUILD_STEP_OUTPUT := $(nanohub_output)
+LOCAL_LDFLAGS += -Wl,-Map,$(nanohub_linked_map)
###############################
include $(BUILD_AUX_EXECUTABLE)
diff --git a/firmware/lib/lib.mk b/firmware/lib/lib.mk
index e2a9ae6..a52a947 100644
--- a/firmware/lib/lib.mk
+++ b/firmware/lib/lib.mk
@@ -51,11 +51,19 @@
LIBC_PATH := $(NANOHUB_DIR)/lib/libc
-SRCS += $(LIBC_PATH)/bcopy.c
SRCS += $(LIBC_PATH)/memcmp.c
#SRCS += $(LIBC_PATH)/memcpy-armv7m.S
SRCS += $(LIBC_PATH)/memcpy.c
SRCS += $(LIBC_PATH)/memmove.c
SRCS += $(LIBC_PATH)/memset.c
SRCS += $(LIBC_PATH)/strcasecmp.c
+SRCS += $(LIBC_PATH)/strncpy.c
SRCS += $(LIBC_PATH)/strlen.c
+
+# C++ support
+
+SRCS += $(LIBC_PATH)/crt.c
+SRCS += $(LIBC_PATH)/aeabi.cpp
+SRCS += $(LIBC_PATH)/cxa.cpp
+SRCS += $(LIBC_PATH)/new.cpp
+CFLAGS += -I$(LIBC_PATH)
diff --git a/firmware/lib/libc/Android.mk b/firmware/lib/libc/Android.mk
index 0b299ba..1558e47 100644
--- a/firmware/lib/libc/Android.mk
+++ b/firmware/lib/libc/Android.mk
@@ -18,14 +18,13 @@
include $(CLEAR_NANO_VARS)
-src_files := \
- bcopy.c \
- memcmp.c \
- memmove.c \
- memset.c \
- strcasecmp.c \
- strlen.c \
- strncpy.c \
+src_files := \
+ memcmp.c \
+ memmove.c \
+ memset.c \
+ strcasecmp.c \
+ strlen.c \
+ strncpy.c \
LOCAL_MODULE := libnanolibc_os
LOCAL_MODULE_TAGS := optional
@@ -43,6 +42,15 @@
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(src_files)
-LOCAL_SRC_FILES += memcpy.c
+LOCAL_SRC_FILES += \
+ memcpy.c \
+ aeabi.cpp \
+ cxa.cpp \
+ new.cpp \
+ crt.c \
+
+LOCAL_C_INCLUDES = $(LOCAL_PATH)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_C_INCLUDES)
include $(BUILD_NANOHUB_APP_STATIC_LIBRARY)
diff --git a/firmware/lib/libc/aeabi.cpp b/firmware/lib/libc/aeabi.cpp
new file mode 100644
index 0000000..0b9d0bf
--- /dev/null
+++ b/firmware/lib/libc/aeabi.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/*
+ * THis file is based on the template provided in the reference doc:
+ * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0041e/IHI0041E_cppabi.pdf
+ *
+ * ARM reference implementation is not changed, except as follows:
+ *
+ * 1 Function prototypes added to avoid compiler warning "no previous function declaration".
+ * Since all of those are internal functions presumably exclusively used by the compiler,
+ * I decided not to provide header file for those and embed function prototypes in the source.
+ *
+ * 2 Methods calling into __cxa_*() primitives;
+ * I decided to not implement such __cxa_*() primitives, and code the functionality directly in aeabi.
+ * this works because the toolchain we use is generating calls to aeabi, and not generic calls.
+ * Decision was made to simplify the solution, because generic code must take care of more corner
+ * cases than necessary in ARM case.
+ * strictly speaking, aeabi.cpp is ARM-specific and should be annotated as such.
+ * This is easy to do in Android.mk build, but not that easy with original Makefile build.
+ * For now, I'm going to ignore both the missing ARM-specific annotation, and missing
+ * certain __cxa_*() calls; I'll deal with both when it comes to that (i.e. when we actually
+ * have an offending use case).
+ *
+ * 3 __aeabi_atexit() was originally calling __cxa_atexit(); I changed that to do-nothing stub;
+ * this is because dynamic registration of destructors as per standard would require one to reserve
+ * sizeof(uintptr_t) * 32 bytes (i.e. 128 bytes on ARM Cortex M4) to comply with standard,
+ * and on top of that, be able to register variable amount of destructor methods (which may be of any size).
+ * possible solution would be to reserve extra space for BSS as boot time, and release extra space
+ * after init is done, however this does not solve entire problem, only global part of it, since
+ * local static registration may happen at any time.
+ * Another possible solution is to provide size of destructor allocation heap at build time;
+ * I reserved a field for that in application data segment for future use.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cxxabi.h>
+
+using namespace __cxxabiv1;
+
+namespace __aeabiv1 {
+
+using ::std::size_t;
+
+// Note: Only the __aeabi_* names are exported.
+// array_cookie, cookie_size, cookie_of, etc. are presented for exposition only.
+// They are not expected to be available to users, but implementers may find them useful.
+struct array_cookie {
+ size_t element_size; // element_size != 0
+ size_t element_count;
+};
+// The struct array_cookie fields and the arguments element_size and element_count
+// are ordered for convenient use of LDRD/STRD on architecture 5TE and above.
+const size_t cookie_size = sizeof(array_cookie);
+
+// cookie_of() takes a pointer to the user array and returns a reference to the cookie.
+inline array_cookie& cookie_of(void* user_array)
+{
+ return reinterpret_cast<array_cookie*>(user_array)[-1];
+}
+
+// element_size_of() takes a pointer to the user array and returns a reference to the
+// element_size field of the cookie.
+inline size_t& element_size_of(void* user_array)
+{
+ return cookie_of(user_array).element_size;
+}
+
+// element_count_of() takes a pointer to the user array and returns a reference to the
+// element_count field of the cookie.
+inline size_t& element_count_of(void* user_array)
+{
+ return cookie_of(user_array).element_count;
+}
+
+// user_array_of() takes a pointer to the cookie and returns a pointer to the user array.
+inline void* user_array_of(array_cookie* cookie_address)
+{
+ return cookie_address + 1;
+}
+
+extern "C" void* __aeabi_vec_ctor_nocookie_nodtor(void* user_array,
+ void* (*constructor)(void*),
+ size_t element_size, size_t element_count);
+extern "C" void* __aeabi_vec_ctor_cookie_nodtor(array_cookie* cookie,
+ void*(*constructor)(void*),
+ size_t element_size, size_t element_count);
+extern "C" void* __aeabi_vec_cctor_nocookie_nodtor(void* user_array_dest,
+ void* user_array_src,
+ size_t element_size, size_t element_count,
+ void* (*copy_constructor)(void*, void*));
+extern "C" void* __aeabi_vec_new_cookie_noctor(size_t element_size, size_t element_count);
+extern "C" int __aeabi_atexit(void* object, void (*destroyer)(void*), void* dso_handle);
+extern "C" void __aeabi_vec_delete3_nodtor(void* user_array, void (*dealloc)(void*, size_t));
+extern "C" void __aeabi_vec_delete3(void* user_array, void* (*destructor)(void*),
+ void (*dealloc)(void*, size_t));
+extern "C" void __aeabi_vec_delete(void* user_array, void* (*destructor)(void*));
+extern "C" void* __aeabi_vec_dtor_cookie(void* user_array, void* (*destructor)(void*));
+extern "C" void* __aeabi_vec_dtor(void* user_array,
+ void* (*destructor)(void*),
+ size_t element_size, size_t element_count);
+extern "C" void* __aeabi_vec_new_cookie(size_t element_size, size_t element_count,
+ void* (*constructor)(void*),
+ void* (*destructor)(void*));
+extern "C" void* __aeabi_vec_new_cookie_nodtor(size_t element_size,
+ size_t element_count,
+ void* (*constructor)(void*));
+extern "C" void* __aeabi_vec_new_nocookie(size_t element_size, size_t element_count,
+ void* (*constructor)(void*));
+
+extern "C" void* __aeabi_vec_ctor_nocookie_nodtor(void* user_array,
+ void* (*constructor)(void*),
+ size_t element_size, size_t element_count)
+{
+ if (constructor != nullptr) {
+ uintptr_t addr = reinterpret_cast<uintptr_t>(user_array);
+ for (size_t i = 0; i < element_count; ++i, addr += element_size) {
+ constructor(reinterpret_cast<void*>(addr));
+ }
+ }
+ return user_array;
+}
+
+// __aeabi_vec_ctor_cookie_nodtor is like __aeabi_vec_ctor_nocookie_nodtor but sets
+// cookie fields and returns user_array. The parameters are arranged to make STRD
+// usable. Does nothing and returns NULL if cookie is NULL.
+extern "C" void* __aeabi_vec_ctor_cookie_nodtor(array_cookie* cookie,
+ void*(*constructor)(void*),
+ size_t element_size, size_t element_count)
+{
+ if (cookie == nullptr) {
+ return nullptr;
+ } else {
+ cookie->element_size = element_size;
+ cookie->element_count = element_count;
+ return __aeabi_vec_ctor_nocookie_nodtor(user_array_of(cookie), constructor,
+ element_size, element_count);
+ }
+}
+
+extern "C" void* __aeabi_vec_cctor_nocookie_nodtor(void* user_array_dest,
+ void* user_array_src,
+ size_t element_size, size_t element_count,
+ void* (*copy_constructor)(void*, void*))
+{
+ if (copy_constructor != nullptr) {
+ uintptr_t src_addr = reinterpret_cast<uintptr_t>(user_array_src);
+ uintptr_t dest_addr = reinterpret_cast<uintptr_t>(user_array_dest);
+ for (size_t i = 0; i < element_count; ++i, src_addr += element_size, dest_addr += element_size) {
+ copy_constructor(reinterpret_cast<void*>(dest_addr), reinterpret_cast<void*>(src_addr));
+ }
+ }
+ return user_array_dest;
+}
+
+extern "C" void* __aeabi_vec_new_cookie_noctor(size_t element_size, size_t element_count)
+{
+ array_cookie* cookie = reinterpret_cast<array_cookie*>(
+ ::operator new[](element_count * element_size + cookie_size)
+ );
+ cookie->element_size = element_size;
+ cookie->element_count = element_count;
+ return user_array_of(cookie);
+}
+
+extern "C" void* __aeabi_vec_new_nocookie(size_t element_size, size_t element_count,
+ void* (*constructor)(void*))
+{
+ return __aeabi_vec_ctor_nocookie_nodtor(::operator new[](element_count * element_size),
+ constructor, element_size, element_count);
+}
+
+extern "C" void* __aeabi_vec_new_cookie_nodtor(size_t element_size,
+ size_t element_count,
+ void* (*constructor)(void*))
+{
+ array_cookie* cookie = reinterpret_cast<array_cookie*>(
+ ::operator new[](element_count * element_size + cookie_size)
+ );
+ return __aeabi_vec_ctor_cookie_nodtor(cookie, constructor, element_size, element_count);
+}
+
+extern "C" void* __aeabi_vec_new_cookie(size_t element_size, size_t element_count,
+ void* (*constructor)(void*),
+ void* (*destructor)(void*))
+{
+ return __aeabi_vec_new_cookie_nodtor(element_size, element_count, constructor);
+}
+
+// __aeabi_vec_dtor is like __cxa_vec_dtor but has its parameters reordered and returns
+// a pointer to the cookie (assuming user_array has one).
+// Unlike __cxa_vec_dtor, destructor must not be NULL.
+// user_array must not be NULL.
+extern "C" void* __aeabi_vec_dtor(void* user_array,
+ void* (*destructor)(void*),
+ size_t element_size, size_t element_count)
+{
+ uintptr_t addr = reinterpret_cast<uintptr_t>(user_array);
+ for (size_t i = 0; i < element_count; ++i, addr += element_size) {
+ destructor(reinterpret_cast<void*>(addr));
+ }
+ return &cookie_of(user_array);
+}
+
+// __aeabi_vec_dtor_cookie is only used on arrays that have cookies.
+// __aeabi_vec_dtor is like __cxa_vec_dtor but returns a pointer to the cookie.
+// That is, it takes a pointer to the user array, calls the given destructor on
+// each element (from highest index down to zero) and returns a pointer to the cookie.
+// Does nothing and returns NULL if cookie is NULL.
+// Unlike __cxa_vec_dtor, destructor must not be NULL.
+// Exceptions are handled as in __cxa_vec_dtor.
+// __aeabi_vec_dtor_cookie must not change the element count in the cookie.
+// (But it may corrupt the element size if desired.)
+extern "C" void* __aeabi_vec_dtor_cookie(void* user_array, void* (*destructor)(void*))
+{
+ return user_array == nullptr ? nullptr :
+ __aeabi_vec_dtor(user_array, destructor,
+ element_size_of(user_array),
+ element_count_of(user_array));
+}
+
+extern "C" void __aeabi_vec_delete(void* user_array, void* (*destructor)(void*))
+{
+ ::operator delete[](__aeabi_vec_dtor_cookie(user_array, destructor));
+}
+
+extern "C" void __aeabi_vec_delete3(void* user_array, void* (*destructor)(void*), void (*dealloc)(void*, size_t))
+{
+ if (user_array != NULL) {
+ size_t size = element_size_of(user_array) * element_count_of(user_array) + cookie_size;
+ void *array_cookie = __aeabi_vec_dtor_cookie(user_array, destructor);
+ dealloc(array_cookie, size);
+ }
+}
+
+extern "C" void __aeabi_vec_delete3_nodtor(void* user_array, void (*dealloc)(void*, size_t))
+{
+ if (user_array != NULL) {
+ size_t size = element_size_of(user_array) * element_count_of(user_array) + cookie_size;
+ (*dealloc)(&cookie_of(user_array), size);
+ }
+}
+
+extern "C" int __aeabi_atexit(void* object, void (*destroyer)(void*), void* dso_handle)
+{
+ return 0;
+}
+
+} // namespace __aeabiv1
diff --git a/firmware/lib/libc/crt.c b/firmware/lib/libc/crt.c
new file mode 100644
index 0000000..60363f8
--- /dev/null
+++ b/firmware/lib/libc/crt.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <crt_priv.h>
+
+static void callVectors(const void *from_addr, const void *to_addr)
+{
+ typedef void (* const callVect)(void);
+ callVect *start = (callVect *)from_addr;
+ callVect *end = (callVect *)to_addr;
+ const int32_t step = from_addr < to_addr ? 1 : -1;
+ const int32_t count = step > 0 ? end - start : start - end;
+
+ // basic sanity check
+ if (&start[step * count] != end)
+ return;
+
+ for (; start != end; start += step) {
+ callVect vec = *start;
+ if (vec != NULL)
+ vec();
+ }
+}
+
+void __crt_init(void)
+{
+ extern uint32_t __init_array_start[];
+ extern uint32_t __init_array_end[];
+
+ callVectors(__init_array_start, __init_array_end);
+}
+
+void __crt_exit(void)
+{
+ extern uint32_t __fini_array_start[];
+ extern uint32_t __fini_array_end[];
+ extern uint32_t __bss_end[];
+ extern uint32_t __got_start[];
+
+ // call global destructors
+ callVectors(__fini_array_start, __fini_array_end);
+ if (&__fini_array_end[1] <= __got_start) {
+ // call registered static destructors
+ callVectors(__bss_end + __fini_array_end[0] * (sizeof(uint32_t)), __bss_end);
+ }
+}
diff --git a/firmware/lib/libc/crt_priv.h b/firmware/lib/libc/crt_priv.h
new file mode 100644
index 0000000..b9695fd
--- /dev/null
+++ b/firmware/lib/libc/crt_priv.h
@@ -0,0 +1,7 @@
+#ifndef _LIBC_CRT_PRIV_H_
+#define _LIBC_CRT_PRIV_H_
+
+void __crt_init(void);
+void __crt_exit(void);
+
+#endif /* _LIBC_CRT_PRIV_H_ */
diff --git a/firmware/lib/libc/cxa.cpp b/firmware/lib/libc/cxa.cpp
new file mode 100644
index 0000000..746a507
--- /dev/null
+++ b/firmware/lib/libc/cxa.cpp
@@ -0,0 +1,43 @@
+#include <cstdlib>
+#include <cstdint>
+#include <cxxabi.h>
+
+namespace __cxxabiv1
+{
+// 3.2.6 Pure Virtual Function API
+extern "C" void __cxa_pure_virtual ()
+{
+ while(true);
+}
+
+// 3.2.7 Deleted Virtual Function API
+extern "C" void __cxa_deleted_virtual ()
+{
+ while(true);
+}
+
+// 3.3.2 One-time Construction API
+// NOTE: Implementation does not support threads; no locking involved
+
+extern "C" int
+__cxa_guard_acquire(__guard *_guard)
+{
+ uint8_t *guard = reinterpret_cast<uint8_t*>(_guard);
+ return guard[0] ? 0 : 1;
+}
+
+extern "C" void
+__cxa_guard_release(__guard *_guard)
+{
+ uint8_t *guard = reinterpret_cast<uint8_t*>(_guard);
+ guard[0] = 1;
+}
+
+extern "C" void
+__cxa_guard_abort(__guard *_guard)
+{
+ uint8_t *guard = reinterpret_cast<uint8_t*>(_guard);
+ guard[0] = 0;
+}
+
+} // namespace __cxxabiv1
diff --git a/firmware/lib/libc/new.cpp b/firmware/lib/libc/new.cpp
new file mode 100644
index 0000000..f093d2a
--- /dev/null
+++ b/firmware/lib/libc/new.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 <cstddef>
+#include <cstdlib>
+#include <new>
+
+#include <syscallDo.h>
+
+using std::size_t;
+
+void* operator new(size_t sz)
+{
+ return eOsHeapAlloc(sz);
+}
+
+void* operator new[](size_t sz)
+{
+ return eOsHeapAlloc(sz);
+}
+
+void operator delete(void *p)
+{
+ eOsHeapFree(p);
+}
+
+void operator delete[](void *p)
+{
+ eOsHeapFree(p);
+}
diff --git a/firmware/lib/libm/Android.mk b/firmware/lib/libm/Android.mk
index b91366a..a229ef5 100644
--- a/firmware/lib/libm/Android.mk
+++ b/firmware/lib/libm/Android.mk
@@ -43,8 +43,9 @@
wf_fmod.c \
wf_pow.c \
-LOCAL_CFLAGS := \
- -DARM_MATH_CM4 \
- -D__FPU_PRESENT\
+LOCAL_CFLAGS := \
+ -DARM_MATH_CM4 \
+ -D__FPU_PRESENT \
+ -D_IEEE_LIBM \
include $(BUILD_NANOHUB_APP_STATIC_LIBRARY)
diff --git a/firmware/os/platform/stm32/lkr/app.lkr b/firmware/os/platform/stm32/lkr/app.lkr
index c2196a9..ae934bd 100644
--- a/firmware/os/platform/stm32/lkr/app.lkr
+++ b/firmware/os/platform/stm32/lkr/app.lkr
@@ -81,6 +81,7 @@
.data : {
. = ALIGN(4);
__data_start = ABSOLUTE(.);
+ __dso_handle = ABSOLUTE(__data_start);
*(.data);
*(.data.*);
. = ALIGN(4);
@@ -97,6 +98,7 @@
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
__fini_array_end = ABSOLUTE(.);
+ LONG(0) /* size in 32-bit words, to add to bss section for dynamic destructor registration */
. = ALIGN(4);
__got_start = ABSOLUTE(.);