Fix crash by implementing a custom malloc
Ref https://surma.dev/things/c-to-webassembly/
This commit is contained in:
parent
84b29f542c
commit
609ce12302
3 changed files with 65 additions and 48 deletions
|
@ -1,3 +1,8 @@
|
||||||
# osfs-wasm
|
# osfs-wasm
|
||||||
|
|
||||||
Compiling the Over-Simplified FileSystem to WASM for fun and profit
|
> Compiling the Over-Simplified FileSystem to WASM for fun and profit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EEPROM sizes, ref <https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8867-SEEPROM-Products-Brochure.pdf> (which suggests kilo**bit**s?!) and <http://ww1.microchip.com/downloads/en/DeviceDoc/21189f.pdf> (which suggests KiB)
|
|
@ -31,15 +31,15 @@ task_begin "Compile";
|
||||||
|
|
||||||
echo -e ">>> Working directory is ${HC}${PWD}${RS}" >&2;
|
echo -e ">>> Working directory is ${HC}${PWD}${RS}" >&2;
|
||||||
|
|
||||||
execute clang -v -v -v --target=wasm32 -nostdlib -Wl,--export-all -Wl,--no-entry \
|
execute clang --target=wasm32 -nostdlib -Wl,--export-all -Wl,--no-entry \
|
||||||
-I"${dirpath_include}" \
|
-I"${dirpath_include}" \
|
||||||
-I "${dirpath_walloc}" \
|
-I "${dirpath_walloc}" \
|
||||||
-I "${dirpath_osfs}" \
|
-I "${dirpath_osfs}" \
|
||||||
-o "${dirpath_output}/osfs.wasm" \
|
-o "${dirpath_output}/osfs.wasm" \
|
||||||
"${dirpath_walloc}/walloc.c" \
|
|
||||||
"${dirpath_osfs}/OSFS.cpp" \
|
"${dirpath_osfs}/OSFS.cpp" \
|
||||||
"${dirpath_include}/wrapper.cpp" \
|
"${dirpath_include}/wrapper.cpp" \
|
||||||
;
|
;
|
||||||
|
|
||||||
|
# "${dirpath_walloc}/walloc.c" \
|
||||||
|
|
||||||
task_end "${?}";
|
task_end "${?}";
|
|
@ -1,6 +1,27 @@
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "OSFS.h"
|
#include "OSFS.h"
|
||||||
#include <walloc.h>
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Custom malloc implementation
|
||||||
|
// Initial design ref https://surma.dev/things/c-to-webassembly/ → Building an
|
||||||
|
// allocator
|
||||||
|
|
||||||
|
// This started as a simple bump allocator, but we've turned it into a singleton
|
||||||
|
// allocator that always allocates the same area of memory, since we only want to allocate a single area of memory
|
||||||
|
extern unsigned char __heap_base;
|
||||||
|
|
||||||
|
unsigned int bump_pointer = (unsigned int)&__heap_base;
|
||||||
|
void *malloc(int n) {
|
||||||
|
unsigned int r = bump_pointer; // This works because the heap grows *upwards* in WASM, not downwards
|
||||||
|
// bump_pointer += n;
|
||||||
|
|
||||||
|
return (void *)r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *p) {
|
||||||
|
// lol
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -9,7 +30,7 @@
|
||||||
// strncmp, memset, strncpy ref https://github.com/bezlant/s21_strings
|
// strncmp, memset, strncpy ref https://github.com/bezlant/s21_strings
|
||||||
int strncmp(const char *str1, const char *str2, size_t n) {
|
int strncmp(const char *str1, const char *str2, size_t n) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
if (str1 && str2 && n > 0) {
|
if (str1 && str2 && n > 0) {
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
if (str1[i] == '\0' || str1[i] != str2[i]) {
|
if (str1[i] == '\0' || str1[i] != str2[i]) {
|
||||||
|
@ -18,25 +39,25 @@ int strncmp(const char *str1, const char *str2, size_t n) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
void *memset(void *str, int c, size_t n) {
|
void *memset(void *str, int c, size_t n) {
|
||||||
char *s = (char *)str;
|
char *s = (char *)str;
|
||||||
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
s[i] = c;
|
s[i] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
char *strncpy(char *dest, const char *src, size_t n) {
|
char *strncpy(char *dest, const char *src, size_t n) {
|
||||||
memset(dest, '\0', n);
|
memset(dest, '\0', n);
|
||||||
|
|
||||||
for (size_t i = 0; i < n && src[i]; i++) {
|
for (size_t i = 0; i < n && src[i]; i++) {
|
||||||
dest[i] = src[i];
|
dest[i] = src[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,29 +72,27 @@ OSFS::result result;
|
||||||
uint16_t OSFS::startOfEEPROM = 1;
|
uint16_t OSFS::startOfEEPROM = 1;
|
||||||
uint16_t OSFS::endOfEEPROM = 64; // change w/set_eeprom_size
|
uint16_t OSFS::endOfEEPROM = 64; // change w/set_eeprom_size
|
||||||
|
|
||||||
|
byte *memory = (byte*)malloc((size_t)(64 * 1024)); // virtual EEPROM, default 64KiB
|
||||||
|
|
||||||
byte* memory = (byte*)malloc((size_t)(64*1024)); // virtual EEPROM, default 64KiB
|
void __clear_memory(uint32_t size) {
|
||||||
|
memset(memory, 0, (size_t)(size * 1024));
|
||||||
void __create_memory(uint32_t size) {
|
|
||||||
free((void*)memory);
|
|
||||||
void* memory_raw = malloc((size_t)(size * 1024));
|
|
||||||
memory = (byte*)memory_raw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __create_memory(uint32_t size) {
|
||||||
|
free((void *)memory);
|
||||||
|
void *memory_raw = malloc((size_t)(size * 1024));
|
||||||
|
memory = (byte *)memory_raw;
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
// Error handling
|
// Error handling
|
||||||
|
|
||||||
#define ERROR_OUT_OF_BOUNDS 1
|
#define ERROR_OUT_OF_BOUNDS 1
|
||||||
|
|
||||||
int last_error = 0;
|
int last_error = 0;
|
||||||
|
|
||||||
int get_last_error() {
|
int get_last_error() { return last_error; }
|
||||||
return last_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -81,7 +100,7 @@ int get_last_error() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to set the size of the EEPROM unit to operate on.
|
* Helper function to set the size of the EEPROM unit to operate on.
|
||||||
*
|
*
|
||||||
* @param {uint16_t} size The size of the EEPROM unit, in KiB
|
* @param {uint16_t} size The size of the EEPROM unit, in KiB
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
@ -90,38 +109,31 @@ void set_eeprom_size(uint16_t new_size) {
|
||||||
__create_memory(new_size);
|
__create_memory(new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t get_eeprom_size() {
|
uint16_t get_eeprom_size() { return OSFS::endOfEEPROM; }
|
||||||
return OSFS::endOfEEPROM;
|
uint32_t get_eeprom_size_bytes() { return OSFS::endOfEEPROM * 1024; }
|
||||||
}
|
|
||||||
uint32_t get_eeprom_size_bytes() {
|
|
||||||
return OSFS::endOfEEPROM * 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void OSFS::readNBytes(uint16_t address, unsigned int num, byte *output) {
|
||||||
|
|
||||||
void OSFS::readNBytes(uint16_t address, unsigned int num, byte* output) {
|
|
||||||
// eeprom.read(address, output, num);
|
// eeprom.read(address, output, num);
|
||||||
last_error = 0;
|
last_error = 0;
|
||||||
|
|
||||||
if(address < OSFS::startOfEEPROM || address + num > OSFS::endOfEEPROM * 1024) {
|
|
||||||
last_error = ERROR_OUT_OF_BOUNDS;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < num; i++) {
|
|
||||||
output[i] = memory[address + i];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
void OSFS::writeNBytes(uint16_t address, unsigned int num, const byte* input) {
|
|
||||||
// eeprom.write(address, input, num);
|
|
||||||
last_error = 0;
|
|
||||||
|
|
||||||
if (address < OSFS::startOfEEPROM || address + num > OSFS::endOfEEPROM * 1024) {
|
if (address < OSFS::startOfEEPROM || address + num > OSFS::endOfEEPROM * 1024) {
|
||||||
last_error = ERROR_OUT_OF_BOUNDS;
|
last_error = ERROR_OUT_OF_BOUNDS;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < num; i++) {
|
||||||
|
output[i] = memory[address + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void OSFS::writeNBytes(uint16_t address, unsigned int num, const byte *input) {
|
||||||
|
// eeprom.write(address, input, num);
|
||||||
|
last_error = 0;
|
||||||
|
|
||||||
|
if (address < OSFS::startOfEEPROM || address + num > OSFS::endOfEEPROM * 1024) {
|
||||||
|
last_error = ERROR_OUT_OF_BOUNDS;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < num; i++) {
|
for (unsigned int i = 0; i < num; i++) {
|
||||||
memory[address + i] = input[i];
|
memory[address + i] = input[i];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue