Commit 5cb45b6855

Alex Rønne Petersen <alex@alexrp.com>
2024-10-15 18:33:31
wasm2c: Add big endian support.
I took a slightly unconventional approach to detecting endianness here. We have no compiler/platform-specific preprocessor checks in the stage1 C code today, and I think that's a property worth maintaining.
1 parent 6a364b4
Changed files (2)
stage1/wasi.c
@@ -184,6 +184,26 @@ enum wasi_whence {
     wasi_whence_end = 2,
 };
 
+extern uint16_t load16_align0(const uint8_t *ptr);
+extern uint16_t load16_align1(const uint16_t *ptr);
+extern uint32_t load32_align0(const uint8_t *ptr);
+extern uint32_t load32_align1(const uint16_t *ptr);
+extern uint32_t load32_align2(const uint32_t *ptr);
+extern uint64_t load64_align0(const uint8_t *ptr);
+extern uint64_t load64_align1(const uint16_t *ptr);
+extern uint64_t load64_align2(const uint32_t *ptr);
+extern uint64_t load64_align3(const uint64_t *ptr);
+
+extern void store16_align0(uint8_t *ptr, uint16_t val);
+extern void store16_align1(uint16_t *ptr, uint16_t val);
+extern void store32_align0(uint8_t *ptr, uint32_t val);
+extern void store32_align1(uint16_t *ptr, uint32_t val);
+extern void store32_align2(uint32_t *ptr, uint32_t val);
+extern void store64_align0(uint8_t *ptr, uint64_t val);
+extern void store64_align1(uint16_t *ptr, uint64_t val);
+extern void store64_align2(uint32_t *ptr, uint64_t val);
+extern void store64_align3(uint64_t *ptr, uint64_t val);
+
 extern uint8_t **const wasm_memory;
 extern void wasm__start(void);
 
@@ -362,14 +382,14 @@ static enum wasi_errno DirEntry_lookup(uint32_t dir_fd, uint32_t flags, const ch
 }
 
 static void DirEntry_filestat(uint32_t de, struct wasi_filestat *res_filestat) {
-    res_filestat->dev = 0;
-    res_filestat->ino = de;
-    res_filestat->filetype = des[de].filetype;
-    res_filestat->nlink = 1;
-    res_filestat->size = 0;
-    res_filestat->atim = des[de].atim * UINT64_C(1000000000);
-    res_filestat->mtim = des[de].mtim * UINT64_C(1000000000);
-    res_filestat->ctim = des[de].ctim * UINT64_C(1000000000);
+    store64_align3(&res_filestat->dev, 0);
+    store64_align3(&res_filestat->ino, de);
+    store64_align3(&res_filestat->filetype, des[de].filetype);
+    store64_align3(&res_filestat->nlink, 1);
+    store64_align3(&res_filestat->size, 0);
+    store64_align3(&res_filestat->atim, des[de].atim * UINT64_C(1000000000));
+    store64_align3(&res_filestat->mtim, des[de].mtim * UINT64_C(1000000000));
+    store64_align3(&res_filestat->ctim, des[de].ctim * UINT64_C(1000000000));
 }
 
 static void DirEntry_unlink(uint32_t de) {
@@ -394,8 +414,8 @@ uint32_t wasi_snapshot_preview1_args_sizes_get(uint32_t argv_size, uint32_t argv
         if (i == 1) continue;
         size += strlen(c_argv[i]) + 1;
     }
-    *argv_size_ptr = c_argc - 1;
-    *argv_buf_size_ptr = size;
+    store32_align2(argv_size_ptr, c_argc - 1);
+    store32_align2(argv_buf_size_ptr, size);
     return wasi_errno_success;
 }
 
@@ -413,7 +433,7 @@ uint32_t wasi_snapshot_preview1_args_get(uint32_t argv, uint32_t argv_buf) {
     uint32_t argv_buf_i = 0;
     for (int src_i = 0; src_i < c_argc; src_i += 1) {
         if (src_i == 1) continue;
-        argv_ptr[dst_i] = argv_buf + argv_buf_i;
+        store32_align2(&argv_ptr[dst_i], argv_buf + argv_buf_i);
         dst_i += 1;
         strcpy(&argv_buf_ptr[argv_buf_i], c_argv[src_i]);
         argv_buf_i += strlen(c_argv[src_i]) + 1;
@@ -430,8 +450,8 @@ uint32_t wasi_snapshot_preview1_fd_prestat_get(uint32_t fd, uint32_t res_prestat
 
     if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
 
-    res_prestat_ptr[0] = 0;
-    res_prestat_ptr[1] = strlen(des[fds[fd].de].guest_path);
+    store32_align2(&res_prestat_ptr[0], 0);
+    store32_align2(&res_prestat_ptr[1], strlen(des[fds[fd].de].guest_path));
     return wasi_errno_success;
 }
 
@@ -443,7 +463,7 @@ uint32_t wasi_snapshot_preview1_fd_prestat_dir_name(uint32_t fd, uint32_t path,
 #endif
 
     if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
-    strncpy(path_ptr, des[fds[fd].de].guest_path, path_len);
+        strncpy(path_ptr, des[fds[fd].de].guest_path, path_len);
     return wasi_errno_success;
 }
 
@@ -502,15 +522,16 @@ uint32_t wasi_snapshot_preview1_fd_read(uint32_t fd, uint32_t iovs, uint32_t iov
 
     size_t size = 0;
     for (uint32_t i = 0; i < iovs_len; i += 1) {
+        uint32_t len = load32_align2(&iovs_ptr[i].len);
         size_t read_size = 0;
         if (fds[fd].stream != NULL)
-            read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
+            read_size = fread(&m[load32_align2(&iovs_ptr[i].ptr)], 1, len, fds[fd].stream);
         size += read_size;
-        if (read_size < iovs_ptr[i].len) break;
+        if (read_size < len) break;
     }
 
     if (size > 0) des[fds[fd].de].atim = time(NULL);
-    *res_size_ptr = size;
+    store32_align2(res_size_ptr, size);
     return wasi_errno_success;
 }
 
@@ -530,7 +551,7 @@ uint32_t wasi_snapshot_preview1_fd_filestat_get(uint32_t fd, uint32_t res_filest
     if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io;
     long size = ftell(fds[fd].stream);
     if (size < 0) return wasi_errno_io;
-    res_filestat_ptr->size = size;
+    store64_align3(&res_filestat_ptr->size, size);
     if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
     return wasi_errno_success;
 }
@@ -617,13 +638,14 @@ uint32_t wasi_snapshot_preview1_fd_pwrite(uint32_t fd, uint32_t iovs, uint32_t i
 
     size_t size = 0;
     for (uint32_t i = 0; i < iovs_len; i += 1) {
+        uint32_t len = load32_align2(&iovs_ptr[i].len);
         size_t written_size = 0;
         if (fds[fd].stream != NULL)
-            written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
+            written_size = fwrite(&m[load32_align2(&iovs_ptr[i].ptr)], 1, len, fds[fd].stream);
         else
-            written_size = iovs_ptr[i].len;
+            written_size = len;
         size += written_size;
-        if (written_size < iovs_ptr[i].len) break;
+        if (written_size < len) break;
     }
 
     if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
@@ -633,7 +655,7 @@ uint32_t wasi_snapshot_preview1_fd_pwrite(uint32_t fd, uint32_t iovs, uint32_t i
         des[fds[fd].de].atim = now;
         des[fds[fd].de].mtim = now;
     }
-    *res_size_ptr = size;
+    store32_align2(res_size_ptr, size);
     return wasi_errno_success;
 }
 
@@ -669,8 +691,8 @@ uint32_t wasi_snapshot_preview1_environ_sizes_get(uint32_t environ_size, uint32_
     fprintf(stderr, "wasi_snapshot_preview1_environ_sizes_get()\n");
 #endif
 
-    *environ_size_ptr = 0;
-    *environ_buf_size_ptr = 0;
+    store32_align2(environ_size_ptr, 0);
+    store32_align2(environ_buf_size_ptr, 0);
     return wasi_errno_success;
 }
 
@@ -702,7 +724,7 @@ uint32_t wasi_snapshot_preview1_path_filestat_get(uint32_t fd, uint32_t flags, u
         if (stream != NULL) {
             if (fseek(stream, 0, SEEK_END) >= 0) {
                 long size = ftell(stream);
-                if (size >= 0) res_filestat_ptr->size = size;
+                if (size >= 0) store64_align3(&res_filestat_ptr->size, size);
             }
             fclose(stream);
         }
@@ -718,10 +740,10 @@ uint32_t wasi_snapshot_preview1_fd_fdstat_get(uint32_t fd, uint32_t res_fdstat)
 #endif
 
     if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
-    res_fdstat_ptr->fs_filetype = des[fds[fd].de].filetype;
-    res_fdstat_ptr->fs_flags = fds[fd].fdflags;
-    res_fdstat_ptr->padding = 0;
-    res_fdstat_ptr->fs_rights_inheriting = fds[fd].fs_rights_inheriting;
+    store16_align1(&res_fdstat_ptr->fs_filetype, des[fds[fd].de].filetype);
+    store16_align1(&res_fdstat_ptr->fs_flags, fds[fd].fdflags);
+    store32_align2(&res_fdstat_ptr->padding, 0);
+    store64_align3(&res_fdstat_ptr->fs_rights_inheriting, fds[fd].fs_rights_inheriting);
     return wasi_errno_success;
 }
 
@@ -757,13 +779,14 @@ uint32_t wasi_snapshot_preview1_fd_write(uint32_t fd, uint32_t iovs, uint32_t io
 
     size_t size = 0;
     for (uint32_t i = 0; i < iovs_len; i += 1) {
+        uint32_t len = load32_align2(&iovs_ptr[i].len);
         size_t written_size = 0;
         if (fds[fd].stream != NULL)
-            written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
+            written_size = fwrite(&m[load32_align2(&iovs_ptr[i].ptr)], 1, len, fds[fd].stream);
         else
-            written_size = iovs_ptr[i].len;
+            written_size = len;
         size += written_size;
-        if (written_size < iovs_ptr[i].len) break;
+        if (written_size < len) break;
     }
 
     if (size > 0) {
@@ -771,7 +794,7 @@ uint32_t wasi_snapshot_preview1_fd_write(uint32_t fd, uint32_t iovs, uint32_t io
         des[fds[fd].de].atim = now;
         des[fds[fd].de].mtim = now;
     }
-    *res_size_ptr = size;
+    store32_align2(res_size_ptr, size);
     return wasi_errno_success;
 }
 
@@ -809,7 +832,7 @@ uint32_t wasi_snapshot_preview1_path_open(uint32_t fd, uint32_t dirflags, uint32
 #if LOG_TRACE
         fprintf(stderr, "fd = %u\n", fd_len);
 #endif
-        *res_fd_ptr = fd_len;
+        store32_align2(res_fd_ptr, fd_len);
         fd_len += 1;
     }
     if (lookup_errno != wasi_errno_noent) return lookup_errno;
@@ -867,7 +890,7 @@ uint32_t wasi_snapshot_preview1_path_open(uint32_t fd, uint32_t dirflags, uint32
     fds[fd_len].fdflags = fdflags;
     fds[fd_len].stream = stream;
     fds[fd_len].fs_rights_inheriting = fs_rights_inheriting;
-    *res_fd_ptr = fd_len;
+    store32_align2(res_fd_ptr, fd_len);
     fd_len += 1;
     return wasi_errno_success;
 }
@@ -882,12 +905,12 @@ uint32_t wasi_snapshot_preview1_clock_time_get(uint32_t id, uint64_t precision,
 
     switch (id) {
         case wasi_clockid_realtime:
-            *res_timestamp_ptr = time(NULL) * UINT64_C(1000000000);
+            store64_align3(res_timestamp_ptr, time(NULL) * UINT64_C(1000000000));
             break;
         case wasi_clockid_monotonic:
         case wasi_clockid_process_cputime_id:
         case wasi_clockid_thread_cputime_id:
-            *res_timestamp_ptr = clock() * (UINT64_C(1000000000) / CLOCKS_PER_SEC);
+            store64_align3(res_timestamp_ptr, clock() * (UINT64_C(1000000000) / CLOCKS_PER_SEC));
             break;
         default: return wasi_errno_inval;
     }
@@ -947,19 +970,20 @@ uint32_t wasi_snapshot_preview1_fd_pread(uint32_t fd, uint32_t iovs, uint32_t io
 
     size_t size = 0;
     for (uint32_t i = 0; i < iovs_len; i += 1) {
+        uint32_t len = load32_align2(&iovs_ptr[i].len);
         size_t read_size = 0;
         if (fds[fd].stream != NULL)
-            read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
+            read_size = fread(&m[load32_align2(&iovs_ptr[i].ptr)], 1, len, fds[fd].stream);
         else
             panic("unimplemented");
         size += read_size;
-        if (read_size < iovs_ptr[i].len) break;
+        if (read_size < len) break;
     }
 
     if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
 
     if (size > 0) des[fds[fd].de].atim = time(NULL);
-    *res_size_ptr = size;
+    store32_align2(res_size_ptr, size);
     return wasi_errno_success;
 }
 
@@ -996,7 +1020,7 @@ uint32_t wasi_snapshot_preview1_fd_seek(uint32_t fd, uint64_t in_offset, uint32_
     if (fseek(fds[fd].stream, offset, seek_whence) < 0) return wasi_errno_io;
     long res_offset = ftell(fds[fd].stream);
     if (res_offset < 0) return wasi_errno_io;
-    *res_filesize_ptr = (uint64_t)res_offset;
+    store64_align3(res_filesize_ptr, res_offset);
     return wasi_errno_success;
 }
 
stage1/wasm2c.c
@@ -73,6 +73,8 @@ static void renderExpr(FILE *out, struct InputStream *in) {
     }
 }
 
+static const uint32_t big_endian = 0xff000000;
+
 int main(int argc, char **argv) {
     if (argc != 3) {
         fprintf(stderr, "usage: %s in.wasm.zst out.c\n", argv[0]);
@@ -80,7 +82,7 @@ int main(int argc, char **argv) {
     }
 
     const char *mod = "wasm";
-    bool is_big_endian = false; // TODO
+    bool is_big_endian = *(uint8_t *)&big_endian;
 
     struct InputStream in;
     InputStream_open(&in, argv[1]);
@@ -111,55 +113,55 @@ int main(int argc, char **argv) {
           "           (uint64_t)i32_byteswap(src >> 32) <<  0;\n"
           "}\n"
           "\n", out);
-    fputs("static uint16_t load16_align0(const uint8_t *ptr) {\n"
+    fputs("uint16_t load16_align0(const uint8_t *ptr) {\n"
           "    uint16_t val;\n"
           "    memcpy(&val, ptr, sizeof(val));\n", out);
     if (is_big_endian) fputs("    val = i16_byteswap(val);", out);
     fputs("    return val;\n"
           "}\n"
-          "static uint16_t load16_align1(const uint16_t *ptr) {\n"
+          "uint16_t load16_align1(const uint16_t *ptr) {\n"
           "    uint16_t val;\n"
           "    memcpy(&val, ptr, sizeof(val));\n", out);
     if (is_big_endian) fputs("    val = i16_byteswap(val);", out);
     fputs("    return val;\n"
           "}\n"
-          "static uint32_t load32_align0(const uint8_t *ptr) {\n"
+          "uint32_t load32_align0(const uint8_t *ptr) {\n"
           "    uint32_t val;\n"
           "    memcpy(&val, ptr, sizeof(val));\n", out);
     if (is_big_endian) fputs("    val = i32_byteswap(val);", out);
     fputs("    return val;\n"
           "}\n"
-          "static uint32_t load32_align1(const uint16_t *ptr) {\n"
+          "uint32_t load32_align1(const uint16_t *ptr) {\n"
           "    uint32_t val;\n"
           "    memcpy(&val, ptr, sizeof(val));\n", out);
     if (is_big_endian) fputs("    val = i32_byteswap(val);", out);
     fputs("    return val;\n"
           "}\n"
-          "static uint32_t load32_align2(const uint32_t *ptr) {\n"
+          "uint32_t load32_align2(const uint32_t *ptr) {\n"
           "    uint32_t val;\n"
           "    memcpy(&val, ptr, sizeof(val));\n", out);
     if (is_big_endian) fputs("    val = i32_byteswap(val);", out);
     fputs("    return val;\n"
           "}\n"
-          "static uint64_t load64_align0(const uint8_t *ptr) {\n"
+          "uint64_t load64_align0(const uint8_t *ptr) {\n"
           "    uint64_t val;\n"
           "    memcpy(&val, ptr, sizeof(val));\n", out);
     if (is_big_endian) fputs("    val = i64_byteswap(val);", out);
     fputs("    return val;\n"
           "}\n"
-          "static uint64_t load64_align1(const uint16_t *ptr) {\n"
+          "uint64_t load64_align1(const uint16_t *ptr) {\n"
           "    uint64_t val;\n"
           "    memcpy(&val, ptr, sizeof(val));\n", out);
     if (is_big_endian) fputs("    val = i64_byteswap(val);", out);
     fputs("    return val;\n"
           "}\n"
-          "static uint64_t load64_align2(const uint32_t *ptr) {\n"
+          "uint64_t load64_align2(const uint32_t *ptr) {\n"
           "    uint64_t val;\n"
           "    memcpy(&val, ptr, sizeof(val));\n", out);
     if (is_big_endian) fputs("    val = i64_byteswap(val);", out);
     fputs("    return val;\n"
           "}\n"
-          "static uint64_t load64_align3(const uint64_t *ptr) {\n"
+          "uint64_t load64_align3(const uint64_t *ptr) {\n"
           "    uint64_t val;\n"
           "    memcpy(&val, ptr, sizeof(val));\n", out);
     if (is_big_endian) fputs("    val = i64_byteswap(val);", out);
@@ -199,39 +201,39 @@ int main(int argc, char **argv) {
           "    return i64_ctz(lhs);\n"
           "}\n"
           "\n"
-          "static void store16_align0(uint8_t *ptr, uint16_t val) {\n", out);
+          "void store16_align0(uint8_t *ptr, uint16_t val) {\n", out);
     if (is_big_endian) fputs("    val = i16_byteswap(val);", out);
     fputs("    memcpy(ptr, &val, sizeof(val));\n"
           "}\n"
-          "static void store16_align1(uint16_t *ptr, uint16_t val) {\n", out);
+          "void store16_align1(uint16_t *ptr, uint16_t val) {\n", out);
     if (is_big_endian) fputs("    val = i16_byteswap(val);", out);
     fputs("    memcpy(ptr, &val, sizeof(val));\n"
           "}\n"
-          "static void store32_align0(uint8_t *ptr, uint32_t val) {\n", out);
+          "void store32_align0(uint8_t *ptr, uint32_t val) {\n", out);
     if (is_big_endian) fputs("    val = i32_byteswap(val);", out);
     fputs("    memcpy(ptr, &val, sizeof(val));\n"
           "}\n"
-          "static void store32_align1(uint16_t *ptr, uint32_t val) {\n", out);
+          "void store32_align1(uint16_t *ptr, uint32_t val) {\n", out);
     if (is_big_endian) fputs("    val = i32_byteswap(val);", out);
     fputs("    memcpy(ptr, &val, sizeof(val));\n"
           "}\n"
-          "static void store32_align2(uint32_t *ptr, uint32_t val) {\n", out);
+          "void store32_align2(uint32_t *ptr, uint32_t val) {\n", out);
     if (is_big_endian) fputs("    val = i32_byteswap(val);", out);
     fputs("    memcpy(ptr, &val, sizeof(val));\n"
           "}\n"
-          "static void store64_align0(uint8_t *ptr, uint64_t val) {\n", out);
+          "void store64_align0(uint8_t *ptr, uint64_t val) {\n", out);
     if (is_big_endian) fputs("    val = i64_byteswap(val);", out);
     fputs("    memcpy(ptr, &val, sizeof(val));\n"
           "}\n"
-          "static void store64_align1(uint16_t *ptr, uint64_t val) {\n", out);
+          "void store64_align1(uint16_t *ptr, uint64_t val) {\n", out);
     if (is_big_endian) fputs("    val = i64_byteswap(val);", out);
     fputs("    memcpy(ptr, &val, sizeof(val));\n"
           "}\n"
-          "static void store64_align2(uint32_t *ptr, uint64_t val) {\n", out);
+          "void store64_align2(uint32_t *ptr, uint64_t val) {\n", out);
     if (is_big_endian) fputs("    val = i64_byteswap(val);", out);
     fputs("    memcpy(ptr, &val, sizeof(val));\n"
           "}\n"
-          "static void store64_align3(uint64_t *ptr, uint64_t val) {\n", out);
+          "void store64_align3(uint64_t *ptr, uint64_t val) {\n", out);
     if (is_big_endian) fputs("    val = i64_byteswap(val);", out);
     fputs("    memcpy(ptr, &val, sizeof(val));\n"
           "}\n"