diff --git a/py/objfun.c b/py/objfun.c
index 8fadbc61190ed39d25748e956a129311eb60bcdc..66145f4a657fcae9857eae2d8c9925162a7aea8a 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -9,6 +9,7 @@
 #include "qstr.h"
 #include "obj.h"
 #include "objtuple.h"
+#include "objfun.h"
 #include "runtime0.h"
 #include "runtime.h"
 #include "bc.h"
@@ -150,18 +151,6 @@ mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var
 /******************************************************************************/
 /* byte code functions                                                        */
 
-typedef struct _mp_obj_fun_bc_t {
-    mp_obj_base_t base;
-    mp_obj_dict_t *globals; // the context within which this function was defined
-    machine_uint_t n_args : 15;         // number of arguments this function takes
-    machine_uint_t n_def_args : 15;     // number of default arguments
-    machine_uint_t takes_var_args : 1;  // set if this function takes variable args
-    machine_uint_t takes_kw_args : 1;   // set if this function takes keyword args
-    const byte *bytecode;   // bytecode for the function
-    qstr *args;             // argument names (needed to resolve positional args passed as keywords)
-    mp_obj_t extra_args[];  // values of default args (if any), plus a slot at the end for var args and/or kw args (if it takes them)
-} mp_obj_fun_bc_t;
-
 #if DEBUG_PRINT
 STATIC void dump_args(const mp_obj_t *a, int sz) {
     DEBUG_printf("%p: ", a);
diff --git a/py/objfun.h b/py/objfun.h
new file mode 100644
index 0000000000000000000000000000000000000000..07ca623ece7f8de269fae40b91ba98587aa69d6b
--- /dev/null
+++ b/py/objfun.h
@@ -0,0 +1,12 @@
+typedef struct _mp_obj_fun_bc_t {
+    mp_obj_base_t base;
+    mp_obj_dict_t *globals; // the context within which this function was defined
+    machine_uint_t n_args : 15;         // number of arguments this function takes
+    machine_uint_t n_def_args : 15;     // number of default arguments
+    machine_uint_t takes_var_args : 1;  // set if this function takes variable args
+    machine_uint_t takes_kw_args : 1;   // set if this function takes keyword args
+    const byte *bytecode;   // bytecode for the function
+    qstr *args;             // argument names (needed to resolve positional args passed as keywords)
+    // values of default args (if any), plus a slot at the end for var args and/or kw args (if it takes them)
+    mp_obj_t extra_args[];
+} mp_obj_fun_bc_t;
diff --git a/py/objgenerator.c b/py/objgenerator.c
index 6468aa20db2a942d2ecd04660a8ca59746fd9f6f..9be7fb197b4721425b7b58885c172d2cf4b4db76 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -9,6 +9,7 @@
 #include "runtime.h"
 #include "bc.h"
 #include "objgenerator.h"
+#include "objfun.h"
 
 /******************************************************************************/
 /* generator wrapper                                                          */
@@ -18,11 +19,12 @@ typedef struct _mp_obj_gen_wrap_t {
     mp_obj_t *fun;
 } mp_obj_gen_wrap_t;
 
-mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_args, const mp_obj_t *args, uint n_args2, const mp_obj_t *args2);
+mp_obj_t mp_obj_new_gen_instance(mp_obj_dict_t *globals, const byte *bytecode, uint n_args, const mp_obj_t *args,
+    uint n_args2, const mp_obj_t *args2);
 
 STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
     mp_obj_gen_wrap_t *self = self_in;
-    mp_obj_t self_fun = self->fun;
+    mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t*)self->fun;
     assert(MP_OBJ_IS_TYPE(self_fun, &mp_type_fun_bc));
     int bc_n_args;
     const byte *bc_code;
@@ -34,7 +36,7 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp
         assert(0);
     }
 
-    return mp_obj_new_gen_instance(bc_code, len1, args1, len2, args2);
+    return mp_obj_new_gen_instance(self_fun->globals, bc_code, len1, args1, len2, args2);
 }
 
 const mp_obj_type_t mp_type_gen_wrap = {
@@ -55,6 +57,7 @@ mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun) {
 
 typedef struct _mp_obj_gen_instance_t {
     mp_obj_base_t base;
+    mp_obj_dict_t *globals;
     const byte *code_info;
     const byte *ip;
     mp_obj_t *sp;
@@ -89,9 +92,12 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
     } else {
         *self->sp = send_value;
     }
+    mp_obj_dict_t *old_globals = mp_globals_get();
+    mp_globals_set(self->globals);
     mp_vm_return_kind_t ret_kind = mp_execute_byte_code_2(self->code_info, &self->ip,
         &self->state[self->n_state - 1], &self->sp, (mp_exc_stack_t*)(self->state + self->n_state),
         &self->exc_sp, throw_value);
+    mp_globals_set(old_globals);
 
     switch (ret_kind) {
         case MP_VM_RETURN_NORMAL:
@@ -225,7 +231,8 @@ const mp_obj_type_t mp_type_gen_instance = {
     .locals_dict = (mp_obj_t)&gen_instance_locals_dict,
 };
 
-mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_args, const mp_obj_t *args, uint n_args2, const mp_obj_t *args2) {
+mp_obj_t mp_obj_new_gen_instance(mp_obj_dict_t *globals, const byte *bytecode, uint n_args, const mp_obj_t *args,
+                                 uint n_args2, const mp_obj_t *args2) {
     const byte *code_info = bytecode;
     // get code info size, and skip the line number table
     machine_uint_t code_info_size = bytecode[0] | (bytecode[1] << 8) | (bytecode[2] << 16) | (bytecode[3] << 24);
@@ -239,6 +246,7 @@ mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_args, const mp_obj
     // allocate the generator object, with room for local stack and exception stack
     mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t));
     o->base.type = &mp_type_gen_instance;
+    o->globals = globals;
     o->code_info = code_info;
     o->sp = &o->state[0] - 1; // sp points to top of stack, which starts off 1 below the state
     o->exc_sp = (mp_exc_stack_t*)(o->state + n_state) - 1;
diff --git a/tests/basics/gen_context.py b/tests/basics/gen_context.py
new file mode 100644
index 0000000000000000000000000000000000000000..02f1531467f10f5f04d0e570aeb047f0eacb2130
--- /dev/null
+++ b/tests/basics/gen_context.py
@@ -0,0 +1,9 @@
+import gen_context2
+
+GLOBAL = "GLOBAL"
+
+def gen():
+    print(GLOBAL)
+    yield 1
+
+gen_context2.call(gen())
diff --git a/tests/basics/gen_context2.py b/tests/basics/gen_context2.py
new file mode 100644
index 0000000000000000000000000000000000000000..0d8048afcc9d1fcb0121fa5d0b37c5159ebddd59
--- /dev/null
+++ b/tests/basics/gen_context2.py
@@ -0,0 +1,2 @@
+def call(g):
+    next(g)
diff --git a/unix/main.c b/unix/main.c
index b9b8fe0b9fe9445155d08e906ffbd52df7dc9c15..fd3419a1c7d8f477499ba3e8c7072937677c3626 100644
--- a/unix/main.c
+++ b/unix/main.c
@@ -250,6 +250,7 @@ int usage(char **argv) {
 
 mp_obj_t mem_info(void) {
     printf("mem: total=%d, current=%d, peak=%d\n", m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated());
+    gc_dump_info();
     return mp_const_none;
 }
 
@@ -356,10 +357,6 @@ int main(int argc, char **argv) {
     mp_store_name(qstr_from_str("gc"), (mp_obj_t)&pyb_gc_obj);
 #endif
 
-    microsocket_init();
-#if MICROPY_MOD_TIME
-    time_init();
-#endif
 #if MICROPY_MOD_FFI
     ffi_init();
 #endif
diff --git a/unix/modsocket.c b/unix/modsocket.c
index 8f47a8b157094c3d2a6885087ebe1f53b48f18e9..7b1aaa975dc0ffdea82a7c6c446f498dc2965ca4 100644
--- a/unix/modsocket.c
+++ b/unix/modsocket.c
@@ -322,12 +322,18 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_socket_getaddrinfo_obj, 2, 6, mod
 
 extern mp_obj_type_t sockaddr_in_type;
 
-#define C(name) { #name, name }
+STATIC const mp_map_elem_t mp_module_socket_globals_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_microsocket) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&microsocket_type },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&mod_socket_getaddrinfo_obj },
+#if MICROPY_SOCKET_EXTRA
+    { MP_OBJ_NEW_QSTR(MP_QSTR_sockaddr_in), (mp_obj_t)&sockaddr_in_type },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_htons), (mp_obj_t)&mod_socket_htons_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_inet_aton), (mp_obj_t)&mod_socket_inet_aton_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_gethostbyname), (mp_obj_t)&mod_socket_gethostbyname_obj },
+#endif
 
-STATIC const struct sym_entry {
-    const char *sym;
-    int val;
-} constants[] = {
+#define C(name) { MP_OBJ_NEW_QSTR(MP_QSTR_ ## name), MP_OBJ_NEW_SMALL_INT(name) }
     C(AF_UNIX),
     C(AF_INET),
     C(AF_INET6),
@@ -344,23 +350,22 @@ STATIC const struct sym_entry {
     C(SO_KEEPALIVE),
     C(SO_LINGER),
     C(SO_REUSEADDR),
-
-    {NULL}
+#undef C
 };
 
-#undef C
+STATIC const mp_obj_dict_t mp_module_socket_globals = {
+    .base = {&mp_type_dict},
+    .map = {
+        .all_keys_are_qstrs = 1,
+        .table_is_fixed_array = 1,
+        .used = sizeof(mp_module_socket_globals_table) / sizeof(mp_map_elem_t),
+        .alloc = sizeof(mp_module_socket_globals_table) / sizeof(mp_map_elem_t),
+        .table = (mp_map_elem_t*)mp_module_socket_globals_table,
+    },
+};
 
-void microsocket_init() {
-    mp_obj_t m = mp_obj_new_module(MP_QSTR_microsocket);
-    mp_store_attr(m, MP_QSTR_socket, (mp_obj_t)&microsocket_type);
-#if MICROPY_SOCKET_EXTRA
-    mp_store_attr(m, MP_QSTR_sockaddr_in, (mp_obj_t)&sockaddr_in_type);
-    mp_store_attr(m, MP_QSTR_htons, (mp_obj_t)&mod_socket_htons_obj);
-    mp_store_attr(m, MP_QSTR_inet_aton, (mp_obj_t)&mod_socket_inet_aton_obj);
-    mp_store_attr(m, MP_QSTR_gethostbyname, (mp_obj_t)&mod_socket_gethostbyname_obj);
-#endif
-    mp_store_attr(m, MP_QSTR_getaddrinfo, (mp_obj_t)&mod_socket_getaddrinfo_obj);
-    for (const struct sym_entry *p = constants; p->sym != NULL; p++) {
-        mp_store_attr(m, QSTR_FROM_STR_STATIC(p->sym), MP_OBJ_NEW_SMALL_INT((machine_int_t)p->val));
-    }
-}
+const mp_obj_module_t mp_module_socket = {
+    .base = { &mp_type_module },
+    .name = MP_QSTR_microsocket,
+    .globals = (mp_obj_dict_t*)&mp_module_socket_globals,
+};
diff --git a/unix/modtime.c b/unix/modtime.c
index 032528947c35b3b19dee90d0805f346198738215..a0d7cd046235c7c6cefb0560f173f45a1d10680e 100644
--- a/unix/modtime.c
+++ b/unix/modtime.c
@@ -11,18 +11,28 @@
 #include "runtime.h"
 
 STATIC mp_obj_t mod_time_time() {
+#if MICROPY_ENABLE_FLOAT
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    mp_float_t val = tv.tv_sec + (mp_float_t)tv.tv_usec / 1000000;
+    return mp_obj_new_float(val);
+#else
     return mp_obj_new_int((machine_int_t)time(NULL));
+#endif
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time);
 
 // Note: this is deprecated since CPy3.3, but pystone still uses it.
 STATIC mp_obj_t mod_time_clock() {
-//    return mp_obj_new_int((machine_int_t)clock());
-    // POSIX requires CLOCKS_PER_SEC equals 1000000, so that's what we assume
+#if MICROPY_ENABLE_FLOAT
+    // POSIX requires CLOCKS_PER_SEC equals 1000000, so that's what we assume.
     // float cannot represent full range of int32 precisely, so we pre-divide
     // int to reduce resolution, and then actually do float division hoping
     // to preserve integer part resolution.
     return mp_obj_new_float((float)(clock() / 1000) / 1000.0);
+#else
+    return mp_obj_new_int((machine_int_t)clock());
+#endif
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_clock_obj, mod_time_clock);
 
@@ -41,9 +51,26 @@ STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_obj, mod_time_sleep);
 
-void time_init() {
-    mp_obj_t m = mp_obj_new_module(QSTR_FROM_STR_STATIC("time"));
-    mp_store_attr(m, QSTR_FROM_STR_STATIC("time"), (mp_obj_t)&mod_time_time_obj);
-    mp_store_attr(m, QSTR_FROM_STR_STATIC("clock"), (mp_obj_t)&mod_time_clock_obj);
-    mp_store_attr(m, QSTR_FROM_STR_STATIC("sleep"), (mp_obj_t)&mod_time_sleep_obj);
-}
+STATIC const mp_map_elem_t mp_module_time_globals_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_time) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_clock), (mp_obj_t)&mod_time_clock_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&mod_time_sleep_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mod_time_time_obj },
+};
+
+STATIC const mp_obj_dict_t mp_module_time_globals = {
+    .base = {&mp_type_dict},
+    .map = {
+        .all_keys_are_qstrs = 1,
+        .table_is_fixed_array = 1,
+        .used = sizeof(mp_module_time_globals_table) / sizeof(mp_map_elem_t),
+        .alloc = sizeof(mp_module_time_globals_table) / sizeof(mp_map_elem_t),
+        .table = (mp_map_elem_t*)mp_module_time_globals_table,
+    },
+};
+
+const mp_obj_module_t mp_module_time = {
+    .base = { &mp_type_module },
+    .name = MP_QSTR_time,
+    .globals = (mp_obj_dict_t*)&mp_module_time_globals,
+};
diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h
index cf6e6fae26dd0c0505c3e80caabeb4fe2595fbce..21d11ebeafe6a5500355c33e087b52f270fa01dc 100644
--- a/unix/mpconfigport.h
+++ b/unix/mpconfigport.h
@@ -17,6 +17,12 @@
 #define MICROPY_MOD_SYS_STDFILES    (1)
 #define MICROPY_ENABLE_MOD_CMATH    (1)
 
+extern const struct _mp_obj_module_t mp_module_time;
+extern const struct _mp_obj_module_t mp_module_socket;
+#define MICROPY_EXTRA_BUILTIN_MODULES \
+    { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mp_module_time }, \
+    { MP_OBJ_NEW_QSTR(MP_QSTR_microsocket), (mp_obj_t)&mp_module_socket }, \
+
 // type definitions for the specific machine
 
 #ifdef __LP64__
diff --git a/unix/qstrdefsport.h b/unix/qstrdefsport.h
index 42f20d2657866dddb8601362a26fdd5b954baed9..4de00aa11cda2362f2cb2a8dce841055686afd84 100644
--- a/unix/qstrdefsport.h
+++ b/unix/qstrdefsport.h
@@ -2,26 +2,12 @@
 
 Q(Test)
 
-Q(rawsocket)
-Q(socket)
-Q(sockaddr_in)
-Q(htons)
-Q(inet_aton)
-Q(gethostbyname)
-Q(getaddrinfo)
-Q(microsocket)
 Q(fileno)
 Q(read)
 Q(readall)
 Q(readline)
 Q(write)
 Q(makefile)
-Q(connect)
-Q(bind)
-Q(listen)
-Q(accept)
-Q(recv)
-Q(setsockopt)
 
 Q(FileIO)
 Q(ffimod)
@@ -30,3 +16,38 @@ Q(fficallback)
 Q(ffivar)
 Q(func)
 Q(var)
+
+Q(time)
+Q(clock)
+Q(sleep)
+
+Q(socket)
+Q(sockaddr_in)
+Q(htons)
+Q(inet_aton)
+Q(gethostbyname)
+Q(getaddrinfo)
+Q(microsocket)
+Q(connect)
+Q(bind)
+Q(listen)
+Q(accept)
+Q(recv)
+Q(setsockopt)
+
+Q(AF_UNIX)
+Q(AF_INET)
+Q(AF_INET6)
+Q(SOCK_STREAM)
+Q(SOCK_DGRAM)
+Q(SOCK_RAW)
+
+Q(MSG_DONTROUTE)
+Q(MSG_DONTWAIT)
+
+Q(SOL_SOCKET)
+Q(SO_BROADCAST)
+Q(SO_ERROR)
+Q(SO_KEEPALIVE)
+Q(SO_LINGER)
+Q(SO_REUSEADDR)