diff --git a/quickjs-libc.c b/quickjs-libc.c
index 54a7a15..a64c4d6 100644
--- a/quickjs-libc.c
+++ b/quickjs-libc.c
@@ -385,12 +385,86 @@ fail:
     return JS_EXCEPTION;
 }
 
+#define READALL_CHUNK (10*1024)
+
+static int readall(FILE *f, JSContext *ctx, uint8_t **dataptr, size_t *sizeptr)
+{
+    uint8_t *data = NULL, *temp;
+    size_t size = 0;
+    size_t used = 0;
+    size_t n;
+
+    while (1) {
+        if (used + READALL_CHUNK + 1 > size) {
+            size = used + READALL_CHUNK + 1;
+
+            /* Overflow check. Some ANSI C compilers
+               may optimize this away, though. */
+            if (size <= used) {
+                if (ctx)
+                    js_free(ctx, data);
+                else
+                    free(data);
+                return -1;
+            }
+
+            if (ctx)
+                temp = js_realloc(ctx, data, size);
+            else
+                temp = realloc(data, size);
+
+            if (temp == NULL) {
+                if (ctx)
+                    js_free(ctx, data);
+                else
+                    free(data);
+                return -1;
+            }
+            data = temp;
+        }
+
+        n = fread(data + used, 1, READALL_CHUNK, f);
+        if (n == 0)
+            break;
+
+        used += n;
+    }
+
+    if (ferror(f)) {
+        if (ctx)
+            js_free(ctx, data);
+        else
+            free(data);
+        return -1;
+    }
+
+    if (ctx)
+        temp = js_realloc(ctx, data, used + 1);
+    else
+        temp = realloc(data, used + 1);
+
+    if (temp == NULL) {
+        if (ctx)
+            js_free(ctx, data);
+        else
+            free(data);
+        return -1;
+    }
+    data = temp;
+    data[used] = '\0';
+
+    *dataptr = data;
+    *sizeptr = used;
+
+    return 0;
+}
+
 uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename)
 {
     FILE *f;
     uint8_t *buf;
     size_t buf_len;
-    long lret;
+    long lret = 0;
 
     f = fopen(filename, "rb");
     if (!f)
@@ -398,7 +472,7 @@ uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename)
     if (fseek(f, 0, SEEK_END) < 0)
         goto fail;
     lret = ftell(f);
-    if (lret < 0)
+    if (lret <= 0)
         goto fail;
     /* XXX: on Linux, ftell() return LONG_MAX for directories */
     if (lret == LONG_MAX) {
@@ -414,13 +488,19 @@ uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename)
         buf = malloc(buf_len + 1);
     if (!buf)
         goto fail;
-    if (fread(buf, 1, buf_len, f) != buf_len) {
-        errno = EIO;
+    buf_len = fread(buf, 1, buf_len, f);
+    if (ferror(f)) {
         if (ctx)
             js_free(ctx, buf);
         else
             free(buf);
     fail:
+        // Files in proc and sysfs may not be seekable or may falsely
+        // appear to be of zero size. Try to read them in another way.
+        if (lret == 0 && readall(f, ctx, &buf, pbuf_len) == 0) {
+            fclose(f);
+            return buf;
+        }
         fclose(f);
         return NULL;
     }
