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(.);