diff --git a/.gitignore b/.gitignore index f59f955..717eb68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Important directories. /out -# https://github.com/cirosantilli/linux-kernel-module-cheat#docker +# https://cirosantilli.com/linux-kernel-module-cheat#docker /out.docker /data diff --git a/.travis.yml b/.travis.yml index 6696765..13c8b93 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -# https://github.com/cirosantilli/linux-kernel-module-cheat#travis +# https://cirosantilli.com/linux-kernel-module-cheat#travis language: cpp diff --git a/README.adoc b/README.adoc index 202350f..40cad2a 100644 --- a/README.adoc +++ b/README.adoc @@ -12523,8 +12523,6 @@ Programs under link:userland/c/[] are examples of https://en.wikipedia.org/wiki/ ** `stdlib.h` *** exit **** link:userland/c/abort.c[] -*** malloc -**** link:userland/c/out_of_memory.c[] ** `stdio.h` *** link:userland/c/stderr.c[] *** link:userland/c/getchar.c[] @@ -12533,6 +12531,15 @@ Programs under link:userland/c/[] are examples of https://en.wikipedia.org/wiki/ * Fun ** link:userland/c/infinite_loop.c[] +==== malloc + +Allocate memory! Vs using the stack: https://stackoverflow.com/questions/4584089/what-is-the-function-of-the-push-pop-instructions-used-on-registers-in-x86-ass/33583134#33583134 + +* link:userland/c/malloc.c[]: `malloc` hello world: allocate two ints and use them. +* link:userland/c/out_of_memory.c[]: test how much memory Linux lets us allocate + +LInux 5.1 / glibc 2.29 implements it with the <>. + ==== GCC C extensions ===== C empty struct @@ -12629,6 +12636,26 @@ getconf -a `getconf` is also specified by POSIX at: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html but not the `-a` option which shows all configurations. +==== mmap + +The mmap system call allows advanced memory operations: + +* link:userland/posix/mmap_file.c[]: memory mapped file example + +mmap is notably used to implement the <> function, replacing the previously used break system call. + +Linux adds has several POSIX extension flags to it. + +===== brk + +Previously <>, but was deprecated in favor of <> + +Example: link:userland/glibc/brk.c[] + +The example allocates two ints and uses them, and then deallocates back. + +Bibliography: https://stackoverflow.com/questions/6988487/what-does-the-brk-system-call-do/31082353#31082353 + === Userland multithreading The following sections are related to multithreading in userland: diff --git a/baremetal/arch/aarch64/no_bootloader/wfe_loop.S b/baremetal/arch/aarch64/no_bootloader/wfe_loop.S index 605a1a4..c4e7d98 100644 --- a/baremetal/arch/aarch64/no_bootloader/wfe_loop.S +++ b/baremetal/arch/aarch64/no_bootloader/wfe_loop.S @@ -1,4 +1,4 @@ -/* https://github.com/cirosantilli/linux-kernel-module-cheat#gem5-simulate-time-reached */ +/* https://cirosantilli.com/linux-kernel-module-cheat#gem5-simulate-limit-reached */ #include diff --git a/lkmc.h b/lkmc.h index ce05a93..2bbf376 100644 --- a/lkmc.h +++ b/lkmc.h @@ -28,6 +28,7 @@ void lkmc_assert_memcmp(const void *s1, const void *s2, size_t n, uint32_t line) fprintf(stderr, "error: %s errno = %d, path = %s\n", function, errno, path); \ exit(EXIT_FAILURE); #define LKMC_TMP_EXT ".tmp" +/* Temporary per C source file name that our examples can safely create. */ #define LKMC_TMP_FILE __FILE__ LKMC_TMP_EXT #define LKMC_TMP_FILE_NAMED(name) __FILE__ "__" name LKMC_TMP_EXT #endif diff --git a/lkmc/aarch64.h b/lkmc/aarch64.h index e6c5f74..1c8ad9b 100644 --- a/lkmc/aarch64.h +++ b/lkmc/aarch64.h @@ -67,7 +67,7 @@ main_after_prologue: \ /** Fields of system registers. */ -/* Counter: https://github.com/cirosantilli/linux-kernel-module-cheat#arm-timer */ +/* Counter: https://cirosantilli.com/linux-kernel-module-cheat#arm-timer */ #define LKMC_SYSREG_CNTV_CTL_ENABLE (1 << 0) #define LKMC_SYSREG_CNTV_CTL_IMASK (1 << 1) #define LKMC_SYSREG_CNTV_CTL_ISTATUS (1 << 2) @@ -80,7 +80,7 @@ main_after_prologue: \ /* LKMC_VECTOR_* * - * https://github.com/cirosantilli/linux-kernel-module-cheat#armv8-exception-vector-table-format + * https://cirosantilli.com/linux-kernel-module-cheat#armv8-exception-vector-table-format */ #define LKMC_VECTOR_SYNC_SP0 (0x1) diff --git a/path_properties.py b/path_properties.py index 67b5226..b85b8a6 100644 --- a/path_properties.py +++ b/path_properties.py @@ -486,6 +486,7 @@ path_properties_tuples = ( # LDADD from LSE 'gem5_unimplemented_instruction': True, }, + 'count.cpp': {'more_than_1s': True}, 'sleep_for.cpp': { 'more_than_1s': True, }, diff --git a/run b/run index 6a41af6..7795822 100755 --- a/run +++ b/run @@ -481,7 +481,7 @@ Extra options to append at the end of the emulator command line. else: if self.env['gem5_script'] == 'fs': if self.env['gem5_restore'] is not None: - # https://github.com/cirosantilli/linux-kernel-module-cheat#gem5-checkpoint-internals + # https://cirosantilli.com/linux-kernel-module-cheat#gem5-checkpoint-internals cpt_dirs = self.gem5_list_checkpoint_dirs() cpt_dir = cpt_dirs[-self.env['gem5_restore']] cpt_dirs_sorted_by_tick = sorted(cpt_dirs, key=lambda x: int(x.split('.')[1])) diff --git a/userland/arch/x86_64/xchg.S b/userland/arch/x86_64/xchg.S index 38c4311..b387159 100644 --- a/userland/arch/x86_64/xchg.S +++ b/userland/arch/x86_64/xchg.S @@ -3,14 +3,14 @@ #include LKMC_PROLOGUE - mov $0, %rax - mov $1, %rbx + mov $0, %r12 + mov $1, %r13 - xchg %rbx, %rax - LKMC_ASSERT_EQ(%rax, $1) - LKMC_ASSERT_EQ(%rbx, $0) + xchg %r13, %r12 + LKMC_ASSERT_EQ(%r12, $1) + LKMC_ASSERT_EQ(%r13, $0) - xchg %rbx, %rax - LKMC_ASSERT_EQ(%rax, $0) - LKMC_ASSERT_EQ(%rbx, $1) + xchg %r13, %r12 + LKMC_ASSERT_EQ(%r12, $0) + LKMC_ASSERT_EQ(%r13, $1) LKMC_EPILOGUE diff --git a/userland/c/malloc.c b/userland/c/malloc.c new file mode 100644 index 0000000..ad996eb --- /dev/null +++ b/userland/c/malloc.c @@ -0,0 +1,22 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#malloc */ + +#include +#include +#include + +int main(void) { + size_t bytes = sizeof(int) * 2; + /* Allocate 2 ints. */ + int *is = malloc(bytes); + /* This can happen for example if we ask for too much memory. */ + if (is == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + is[0] = 1; + assert(is[0] == 1); + /* Free the allocated memory. */ + free(is); + return EXIT_SUCCESS; +} + diff --git a/userland/c/out_of_memory.c b/userland/c/out_of_memory.c index 3bbc362..4135598 100644 --- a/userland/c/out_of_memory.c +++ b/userland/c/out_of_memory.c @@ -1,4 +1,4 @@ -/* Let's see how much memory Linux lets us allocate. */ +/* https://cirosantilli.com/linux-kernel-module-cheat#malloc */ #include #include diff --git a/userland/cpp/atomic.cpp b/userland/cpp/atomic.cpp index 39792fe..8daba6a 100644 --- a/userland/cpp/atomic.cpp +++ b/userland/cpp/atomic.cpp @@ -1,4 +1,4 @@ -// https://github.com/cirosantilli/linux-kernel-module-cheat#cpp-multithreading +// https://cirosantilli.com/linux-kernel-module-cheat#cpp-multithreading // // The non-atomic counters have undefined values which get printed: // they are extremely likely to be less than the correct value due to diff --git a/userland/cpp/count.cpp b/userland/cpp/count.cpp index d63038f..5e39513 100644 --- a/userland/cpp/count.cpp +++ b/userland/cpp/count.cpp @@ -1,6 +1,6 @@ // Count to infinity sleeping one second per number. // -// https://github.com/cirosantilli/linux-kernel-module-cheat#cpp-multithreading +// https://cirosantilli.com/linux-kernel-module-cheat#cpp-multithreading #include #include diff --git a/userland/glibc/README.adoc b/userland/glibc/README.adoc new file mode 100644 index 0000000..0bfc9d7 --- /dev/null +++ b/userland/glibc/README.adoc @@ -0,0 +1 @@ +This directory contains glibc extensions to POSIX / ANSI C. diff --git a/userland/glibc/brk.c b/userland/glibc/brk.c new file mode 100644 index 0000000..47e5e9b --- /dev/null +++ b/userland/glibc/brk.c @@ -0,0 +1,24 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#brk */ + +#define _GNU_SOURCE +#include +#include + +int main(void) { + void *b = sbrk(0); + int *p = (int *)b; + + /* Move it 2 ints forward */ + brk(p + 2); + + /* Use the ints. */ + *p = 1; + *(p + 1) = 2; + assert(*p == 1); + assert(*(p + 1) == 2); + + /* Deallocate back. */ + brk(b); + + return 0; +} diff --git a/userland/glibc/build b/userland/glibc/build new file mode 120000 index 0000000..ab18017 --- /dev/null +++ b/userland/glibc/build @@ -0,0 +1 @@ +../build \ No newline at end of file diff --git a/userland/glibc/test b/userland/glibc/test new file mode 120000 index 0000000..419df4f --- /dev/null +++ b/userland/glibc/test @@ -0,0 +1 @@ +../test \ No newline at end of file diff --git a/userland/linux/sysconf.c b/userland/linux/sysconf.c index cd27b77..e07f9da 100644 --- a/userland/linux/sysconf.c +++ b/userland/linux/sysconf.c @@ -1,4 +1,4 @@ -/* https://github.com/cirosantilli/linux-kernel-module-cheat#sysconf */ +/* https://cirosantilli.com/linux-kernel-module-cheat#sysconf */ #define _XOPEN_SOURCE 700 #include diff --git a/userland/posix/count.c b/userland/posix/count.c index df4380d..2e926c7 100644 --- a/userland/posix/count.c +++ b/userland/posix/count.c @@ -1,6 +1,6 @@ /* Count to infinity with 1 second sleep between each increment. * - * https://github.com/cirosantilli/linux-kernel-module-cheat#unistd-h + * https://cirosantilli.com/linux-kernel-module-cheat#unistd-h * * Sample application: https://cirosantilli.com/linux-kernel-module-cheat#gdb-step-debug-userland-custom-init */ diff --git a/userland/posix/count_to.c b/userland/posix/count_to.c index 9501aab..d9fd84e 100644 --- a/userland/posix/count_to.c +++ b/userland/posix/count_to.c @@ -1,6 +1,6 @@ /* Count up to a given number 1 second sleep between each increment. * - * https://github.com/cirosantilli/linux-kernel-module-cheat#unistd-h + * https://cirosantilli.com/linux-kernel-module-cheat#unistd-h * * We need a separate program for this from count.c because count.c * is also usable as an init process, where we can't control the CLI diff --git a/userland/posix/mmap_file.c b/userland/posix/mmap_file.c new file mode 100644 index 0000000..831d660 --- /dev/null +++ b/userland/posix/mmap_file.c @@ -0,0 +1,118 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#mmap + * + * Example of mmap on files. + * + * Create a file, mmap to it, write to maped memory, close. + * + * Then read the file and confirm it was written to. + * + * Implemented in Linux by the mmap syscall. + */ + +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int main(void) { + char *filepath = LKMC_TMP_FILE; + enum Constexpr { NUMINTS = 4 }; + size_t filesize = NUMINTS * sizeof(int); + + int i; + int fd; + int result; + /* mmapped array of int's */ + int *map; + + /* Write to file with mmap. */ + { + /* `O_WRONLY` is not sufficient when mmaping, need `O_RDWR`.*/ + fd = open(filepath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd == -1) { + perror("open"); + exit(EXIT_FAILURE); + } + + /* Set fd position and write to it to strech the file. */ + result = lseek(fd, filesize - 1, SEEK_SET); + if (result == -1) { + close(fd); + perror("lseek"); + exit(EXIT_FAILURE); + } + + /* Write something to the file to actually strech it. */ + result = write(fd, "", 1); + if (result != 1) { + close(fd); + perror("write"); + exit(EXIT_FAILURE); + } + + /* Do the actual mapping call. */ + map = mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) { + close(fd); + perror("mmap"); + exit(EXIT_FAILURE); + } + + /* Write int's to the file as if it were memory because MAP_SHARED was used. */ + for (i = 0; i < NUMINTS; ++i) { + map[i] = i; + } + + /* Free mmapped memory. */ + if (munmap(map, filesize) == -1) { + perror("munmap"); + exit(EXIT_FAILURE); + } + + /* Un-mmaping doesn't close the file, so we still need to do that. */ + if (close(fd) == -1) { + perror("close"); + exit(EXIT_FAILURE); + } + } + + /* Read result back in. */ + { + fd = open(filepath, O_RDONLY, 0); + if (fd == -1) { + perror("open"); + exit(EXIT_FAILURE); + } + + map = mmap(0, filesize, PROT_READ, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) { + close(fd); + perror("mmap"); + exit(EXIT_FAILURE); + } + + assert(map[1] == 1); + + /* Segmentation fault because no `PROT_WRITE`: */ + /*map[1] = 2;*/ + + if (munmap(map, filesize) == -1) { + perror("munmap"); + exit(EXIT_FAILURE); + } + + if (close(fd) == -1) { + perror("close"); + exit(EXIT_FAILURE); + } + } + + return EXIT_SUCCESS; +} diff --git a/userland/posix/pthread_count.c b/userland/posix/pthread_count.c index c6b9a25..4bc3e81 100644 --- a/userland/posix/pthread_count.c +++ b/userland/posix/pthread_count.c @@ -1,6 +1,6 @@ /* count to infinity in n threads. * - * https://github.com/cirosantilli/linux-kernel-module-cheat#pthreads + * https://cirosantilli.com/linux-kernel-module-cheat#pthreads * * Useful if you need to keep several threads around * to test something. diff --git a/userland/posix/pthread_deadlock.c b/userland/posix/pthread_deadlock.c index 26aef9f..e409249 100644 --- a/userland/posix/pthread_deadlock.c +++ b/userland/posix/pthread_deadlock.c @@ -1,6 +1,6 @@ /* Let's see a trivial deadlock in action to feel the joys of multithreading. * - * https://github.com/cirosantilli/linux-kernel-module-cheat#pthreads + * https://cirosantilli.com/linux-kernel-module-cheat#pthreads * * Exit successfully immediately without any arguments: * diff --git a/userland/posix/pthread_self.c b/userland/posix/pthread_self.c index a5e08b5..3f5c4d4 100644 --- a/userland/posix/pthread_self.c +++ b/userland/posix/pthread_self.c @@ -1,7 +1,7 @@ /* Spawn N threads that print their TID with pthread_self and other * ID-like information for multiple threads. * - * https://github.com/cirosantilli/linux-kernel-module-cheat#pthreads + * https://cirosantilli.com/linux-kernel-module-cheat#pthreads * * Sample usage: * diff --git a/userland/posix/sysconf.c b/userland/posix/sysconf.c index 8c39d87..f2bf870 100644 --- a/userland/posix/sysconf.c +++ b/userland/posix/sysconf.c @@ -1,4 +1,4 @@ -/* https://github.com/cirosantilli/linux-kernel-module-cheat#sysconf */ +/* https://cirosantilli.com/linux-kernel-module-cheat#sysconf */ #define _XOPEN_SOURCE 700 #include