aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--README.md1
-rw-r--r--lang/c/Makefile56
-rw-r--r--lang/c/counted_by.c67
4 files changed, 127 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 448af94..b892347 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,6 @@ arch/riscv/machine/machine
# kernel/dtm
kernel/dtm/modules.order
kernel/dtm/Module.symvers
+
+# lang/c
+lang/c/counted_by \ No newline at end of file
diff --git a/README.md b/README.md
index 1804b5e..4c95800 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,7 @@ A bunch of code that messes with low level stuff. That is:
- `user/`: user space programs that either delve into RISC-V assembly or that
interface the Linux Kernel on the RISC-V architecture.
- `kernel/dtm`: simple kernel module showcasing the API from the `of` driver.
+- `lang/c`: miscellanous code on the C programming language.
A lot of this is not taken solely from my brain, and I will give credit whenever
it's relevant to each piece of code. For the rest of the code, the GPLv3+
diff --git a/lang/c/Makefile b/lang/c/Makefile
new file mode 100644
index 0000000..4979e7a
--- /dev/null
+++ b/lang/c/Makefile
@@ -0,0 +1,56 @@
+##
+# By default everything is silent. If you want to change this behavior, simply
+# assign V=1 when calling make.
+
+V =
+ifeq ($(strip $(V)),)
+ E = @echo
+ Q = @
+else
+ E = @\#
+ Q =
+endif
+
+##
+# Compile options. You can use CROSS_COMPILE just like on the Linux Kernel.
+
+CC = $(CROSS_COMPILE)gcc
+LD = $(CROSS_COMPILE)ld
+CCFLAGS = -Werror -Wpedantic -Wall -Wextra -Wcast-align -Wcast-qual -Winit-self \
+ -Wmissing-include-dirs -Wredundant-decls -Wshadow -Wsign-conversion \
+ -Wswitch-default -Wundef -Wunreachable-code -Wmissing-noreturn \
+ -D_FORTIFY_SOURCE=3 -fstrict-flex-arrays=3 -fsanitize=bounds-strict
+ # NOTE: last line: special flags for the examples :)
+LDFLAGS =
+
+
+# You can pass an optional `DEBUG` variable to manipulate the build type.
+DEBUG =
+ifeq ($(strip $(DEBUG)),)
+ CCFLAGS += -O3
+else
+ CCFLAGS += -g
+endif
+
+##
+# Paths.
+
+SRC = $(wildcard *.c)
+EXES = $(SRC:.c=)
+
+##
+# Targets
+
+.PHONY: all
+all: clean $(EXES)
+
+.PHONY: build
+build: $(EXES)
+
+.c:
+ $(E) " CC " $(*F)
+ $(Q) $(CC) $(CCFLAGS) $< -o $@
+
+.PHONY: clean
+clean:
+ $(Q) rm -f $(EXES)
diff --git a/lang/c/counted_by.c b/lang/c/counted_by.c
new file mode 100644
index 0000000..09d4699
--- /dev/null
+++ b/lang/c/counted_by.c
@@ -0,0 +1,67 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+struct foo {
+ uint64_t a;
+ uint64_t b;
+};
+
+struct bounded_flex_t {
+ uint64_t count;
+
+ // NOTE: try to move this member somewhere else and you will get:
+ // counted_by.c:13:20: error: flexible array member not at end of struct
+ struct foo flex_array[] __attribute__((counted_by(count)));
+};
+
+void free_flex(struct bounded_flex_t **flex)
+{
+ struct bounded_flex_t *ptr = *flex;
+
+ printf("Freeing a flexible array of %ld members.\n", ptr->count);
+ free(*flex);
+}
+
+__attribute__((noreturn)) void die(const char *const str)
+{
+ fprintf(stderr, str);
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char *argv[])
+{
+ uint64_t len = 1;
+
+ if (argc == 2) {
+ len = (uint64_t) strtol(argv[1], NULL, 10);
+ if (!len) {
+ die("error: bad integer value!\n");
+ }
+ } else if (argc > 2) {
+ die("error: only pass one argument maximum!\n");
+ }
+
+ // That's a mouthful :P
+ struct bounded_flex_t *flex __attribute__((cleanup(free_flex))) = malloc(sizeof(struct bounded_flex_t) + (len * sizeof(struct foo)));
+ if (!flex) {
+ die("error: could not allocate memory for it");
+ }
+
+ // NOTE: if this is not the first thing that we do, and we use 'len' for the
+ // for loop below, then we will get a runtime error from the array bound
+ // checker. Hence, pretty much like in Rust :)
+ flex->count = len;
+
+ uint64_t accumulator = 0;
+ for (uint64_t i = 0; i < flex->count; i++) {
+ flex->flex_array[i] = (struct foo){ .a = accumulator, .b = accumulator + 1};
+ accumulator++;
+ }
+
+ for (uint64_t i = 0; i < flex->count; i++) {
+ printf("%ld: .a = %ld, .b = %ld\n", i, flex->flex_array[i].a, flex->flex_array[i].b);
+ }
+}