Comment: | updates |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
f5b7fa57628ccb9c61d9729b95f3861e |
User & Date: | lexi on 2019-06-27 05:52:40 |
Other Links: | manifest | tags |
2019-06-27
| ||
09:57 | add in mechanism to generate syscall tables for x86 linux check-in: 860229e8ce user: lexi tags: trunk | |
05:52 | updates check-in: f5b7fa5762 user: lexi tags: trunk | |
2019-06-26
| ||
13:59 | fix typo check-in: 4eb81c9227 user: lexi tags: trunk | |
Deleted arch/x86.lin.32.inc version [32148439cc].
1 -; vim: ft=nasm 2 -%define lin.call.exit 1 3 -%define lin.call.fork 2 4 -%define lin.call.read 3 5 -%define lin.call.write 4 6 -%define lin.call.open 5 7 -%define lin.call.close 6 8 - 9 -%define lin.call.chdir 12 10 - 11 -%define lin.reg.n 6 12 -%define lin.reg.0 eax 13 -%define lin.reg.1 ebx 14 -%define lin.reg.2 ecx 15 -%define lin.reg.3 edx 16 -%define lin.reg.4 esi 17 -%define lin.reg.5 edi 18 - 19 -%define lin.call int 0x80 ; sysenter is allegedly the 20 - ; politically correct option but it does not actually 21 - ; appear to work without a whole lot of extra bullshit 22 - 23 -; todo: learn vdsos
Added arch/x86.lin.32.s version [7c5909e17f].
1 +; vim: ft=nasm 2 +%define sys.exit 1 3 +%define sys.fork 2 4 +%define sys.read 3 5 +%define sys.write 4 6 +%define sys.open 5 7 +%define sys.close 6 8 +%define sys.chdir 12 9 + 10 +%define sys.reg.n 6 11 +%define sys.reg.0 eax 12 +%define sys.reg.1 ebx 13 +%define sys.reg.2 ecx 14 +%define sys.reg.3 edx 15 +%define sys.reg.4 esi 16 +%define sys.reg.5 edi 17 + 18 +%define sys.call int 0x80 ; sysenter is allegedly the 19 + ; politically correct option but it does not actually 20 + ; appear to work without a whole lot of extra bullshit 21 + 22 +; todo: learn vdsos
Deleted arch/x86.lin.64.inc version [abfe39789c].
1 -; vim: ft=nasm 2 -%define lin.call.exit 60 3 -%define lin.call.fork 57 4 -%define lin.call.read 0 5 -%define lin.call.write 1 6 -%define lin.call.open 2 7 -%define lin.call.close 3 8 - 9 -%define lin.call.chdir 80 10 - 11 -%define lin.reg.n 6 12 -%define lin.reg.0 rax 13 -%define lin.reg.1 rdi 14 -%define lin.reg.2 rsi 15 -%define lin.reg.3 rdx 16 -%define lin.reg.4 r10 17 -%define lin.reg.6 r8 18 -%define lin.reg.7 r9 19 - 20 -%define lin.c.0 rdi 21 -%define lin.c.1 rsi 22 -%define lin.c.2 rdx 23 -%define lin.c.3 rcx 24 -%define lin.c.4 r8 25 -%define lin.c.5 r9 26 - 27 -%define lin.call syscall 28 -; todo: learn vdsos
Added arch/x86.lin.64.s version [fcbc285104].
1 +;; abi definition file 2 +;; macros: 3 +;; * sys: syscall64 wrapper 4 +;; * ccall: automatically generate code to call a C function 5 +;; with any number of arguments 6 + 7 +; syscall ops 8 +%define sys.call syscall 9 +; syscall numbers 10 +%define sys.write 1 11 +%define sys.brk 12 12 +%define sys.exit 60 13 + 14 +; register order for syscall convention 15 +%define sys.reg.0 rax 16 +%define sys.reg.1 rdi 17 +%define sys.reg.2 rsi 18 +%define sys.reg.3 rdx 19 +%define sys.reg.4 r10 20 +%define sys.reg.5 r8 21 +%define sys.reg.6 r9 22 + 23 +; register order for ccall convention 24 +%define ccall.reg.ct 6 25 +%define ccall.reg.0 rdi 26 +%define ccall.reg.1 rsi 27 +%define ccall.reg.2 rdx 28 +%define ccall.reg.3 rcx 29 +%define ccall.reg.4 r8 30 +%define ccall.reg.5 r9 31 + 32 +%macro sys 1-8 33 + %assign i 0 34 + %rep %0 35 + mov sys.reg. %+ i, %1 ; i'm actually shocked this worked 36 + %rotate 1 37 + %assign i i+1 38 + %endrep 39 + syscall 40 +%endmacro 41 + 42 +%macro sys.prep 1-8 43 + ; for when we need to modify parameters before we 44 + ; make the actual call. 45 + %assign i 0 46 + %rep %0 47 + mov sys.reg. %+ i, %1 48 + %rotate 1 49 + %assign i i+1 50 + %endrep 51 +%endmacro 52 + 53 +%macro ccall 1-* 54 + %if %0 > ccall.reg.ct 55 + %assign ct ccall.reg.ct 56 + %else 57 + %assign ct %0-1 58 + %endif 59 + %assign i 0 60 + %rotate 1 61 + %rep ct 62 + ; if the function is well-behaved, all its arguments fit 63 + ; in registers. if not, things get ugly. see below. 64 + mov ccall.reg. %+ i, %1 65 + %assign i i+1 66 + %rotate 1 67 + %endrep 68 + %if %0 > ccall.reg.ct 69 + ; if there are more parameters to a C function than the 70 + ; number of permitted registers, they must be pushed in 71 + ; reverse order to the stack. 72 + ; keep your function signatures under control, people. 73 + %assign ct (%0-ct)-1 74 + %rotate ct 75 + %rep ct 76 + %rotate -1 77 + push %1 78 + %endrep 79 + %rotate ct 80 + push rsp ; it's our responsibility to preserve the stack 81 + %endif 82 + call %1 83 + %if %0 > ccall.reg.ct 84 + ; the extra arguments are still on the stack; time to 85 + ; dump them back into the Garbage Zone 86 + pop rsp 87 + %endif 88 +%endmacro
Added kfile/file.h version [7ec69a3e9e].
1 +#ifndef KIfile 2 +#define KIfile 3 + 4 +#endif
Added kfile/kfile.md version [194f78820a].
1 +# kfile
Added kfile/makefile version [f0df06fe05].
1 +include ../modmake
Added kgraft/exe.attach.c version [a7ffc6f8bf].
Added kgraft/graft.h version [510bcb01f3].
1 +#ifndef KIgraft 2 +#define KIgraft 3 + 4 +#endif
Added kgraft/kgraft.md version [74aca3ba50].
1 +# kgraft
Added kgraft/makefile version [f0df06fe05].
1 +include ../modmake
Added kio/io.h version [247977844e].
1 +#ifndef KIio 2 +#define KIio 3 + 4 +#endif
Added kio/kio.md version [947bccad05].
1 +# kio
Modified kio/kio_posix_fd_write.x86.lin.32.s from [c48aae0264] to [7b77d86bab].
1 1 bits 32 2 2 global kio_posix_fd_write 3 3 4 -%include "../arch/x86.lin.32.inc" 4 +%include "../arch/x86.lin.32.s" 5 5 ; vim: ft=nasm 6 6 7 7 kio_posix_fd_write: 8 - mov lin.reg.0, lin.call.write 9 - mov lin.reg.1, [esp + 4] ; holy god but this took the most 10 - mov lin.reg.2, [esp + 8] ; stupidly long time to fucking 11 - mov lin.reg.3, [esp + 12]; figure out 12 - lin.call 8 + mov sys.reg.0, sys.call.write 9 + mov sys.reg.1, [esp + 4] ; holy god but this took the most 10 + mov sys.reg.2, [esp + 8] ; stupidly long time to fucking 11 + mov sys.reg.3, [esp + 12]; figure out 12 + sys.call 13 13 ret 14 14
Modified kio/kio_posix_fd_write.x86.lin.64.s from [4a36b27408] to [b72b3eff18].
1 1 bits 64 2 2 global kio_posix_fd_write 3 3 4 -%include "../arch/x86.lin.64.inc" 4 +%include "../arch/x86.lin.64.s" 5 5 ; vim: ft=nasm 6 6 7 7 kio_posix_fd_write: 8 - mov lin.reg.0, lin.call.write 9 - ; mov lin.reg.1, lin.c.0 - nop 10 - ; mov lin.reg.2, lin.c.1 - nop 11 - ; mov lin.reg.3, lin.c.2 - nop 12 - lin.call 8 + mov sys.reg.0, sys.write 9 + ; mov sys.reg.1, ccall.reg.0 - nop 10 + ; mov sys.reg.2, ccall.reg.1 - nop 11 + ; mov sys.reg.3, ccall.reg.2 - nop 12 + sys.call 13 13 ret 14 14
Modified kio/makefile from [d6a8fa167d] to [f0df06fe05].
1 -kio: posix 2 - 3 -posix: ${OUT}/kio_posix_fd_write.${TARGET}.o 4 - 5 -${OUT}/%.lin.32.o: %.lin.32.s 6 - yasm -felf32 $< -o $@ 7 - 8 -${OUT}/%.lin.64.o: %.lin.64.s 9 - yasm -felf64 $< -o $@ 10 - 1 +include ../modmake
Modified kmem/kmem.md from [e0850f6b30] to [9a7772ee1a].
4 4 5 5 ## module functions 6 6 7 7 **kmem** supplies two module-level functions, used to interact with the `kmptr` container type. 8 8 9 9 * `kmfree(kmptr) → void` - free, downref, or ignore the pasted object as appropriate 10 10 * `kmshred(kmptr) → void` - free, downref, or ignore the pasted object as appropriate. if deallocating, zero its contents 11 - * `kmstat(void*) → kmptr` - convenience function to wrap a pointer to a non-managed object in a `kmptr` struct, so it can be passed to functions that accept arbitrary objects. `kmptr p = kmstat(raw)` is equivalent to `kmptr p = { kmptr_kind_static, raw, NULL }`. 11 + * `kmstat(void*) → kmptr` - convenience function to wrap a pointer to a non-managed object in a `kmptr` struct, so it can be passed to functions that accept arbitrary objects. `kmptr p = kmstat(raw)` is equivalent to `kmptr p = { kmkind_none, raw, NULL }`. 12 12 * `kmtaint(&kmptr) → void` - "taints" a `kmptr` object by setting it to be shredded when freed. this may be desirable if the object pointed to contains privileged information. 13 13 14 14 ## types 15 15 16 16 kmem defines the following types: 17 17 18 + * `enum kmkind` - enumerates allocation strategies 18 19 * `struct kmptr` - abstract pointer object 19 - * `enum kmptr_kind` 20 20 * `struct kmcell` - abstract memory cell 21 - * `enum kmcell_kind` 22 21 * `struct kmref` - a reference-counted cell 23 22 * `struct kmnode` - a node in an allocation tree 24 23 * `struct kmpool` - a memory pool 25 24 26 25 `kmptr` and `kmcell` are both very similar. the difference is that a kmptr points to a region in memory and can be passed around freely. a `kmcell` is the actual in-memory representation of an allocation cell. a `kmcell` cannot be usefully instantiated; rather, it is downcast from an actual cell type (e.g. `kmnode n; kmcell* s = (kmcell*)(&n)`) 27 26 27 + 28 +### kmkind 29 + 30 +`kmkind` is an enum that specifies an allocation function. 31 + 32 + * `kmkind_none` - no allocation 33 + * `kmkind_heap` - heap allocation 34 + * `kmkind_pool` - pool allocation 35 + * `kmkind_ref` - reference-counting allocation 36 + * `kmkind_tree` - tree allocation 37 + 28 38 ### kmptr 29 39 30 40 kmem functions can operate on both raw pointers and the `kmptr` struct type. `kmptr` is a generic struct that can contain any kind of pointer. this is useful if you wish to allocate different objects in different manners, but pass them on into a single interface. 31 41 32 42 memory pointed at by `kmptr` pointers can be freed either with the usual specialized function, or by passing the `kmptr` structure itself to the generic function `kmfree`, which will handle it appropriately, even if it's a pointer to a garbage-collected object or to a static region of memory. 33 43 34 44 a `kmptr` has the following layout: 35 45 36 - * `kmptr_kind kind` - codes the type of pointer 46 + * `kmkind kind` - codes the type of pointer; `kmkind_none` indicates a non-allocated pointer to a static (global or on-stack) object. 37 47 * `kmshred shred` - an enum. if `kmshred_yes`, the value will be zeroed or otherwise made unreadable on free. if no, `kmfree` will consult `src` for shred policy if it is not NULL. 38 48 * `void* ref` - the raw pointer enclosed by `cell` 39 49 * `kmcell* cell` - a pointer to an object enclosure, typically either a memory pool or a referencing-counting object. NULL if not needed. 40 50 41 51 the convenience function `kmstat(void*) → kmptr` wraps a pointer to a static object in a `kmptr` struct. 42 52 43 -#### kmptr_kind 44 - 45 -`kmptr_kind` is an enum with one of the following values. 46 - 47 - * `kmptr_kind_none` - not a valid pointer 48 - * `kmptr_kind_static` - points to a static region of space. `kmptr` instances with this kind will be ignored by `kmfree`. 49 - * `kmptr_kind_heap` - a traditional heap pointer. 50 - * `kmptr_kind_pool` - points to a region stored in a memory pool. 51 - * `kmptr_kind_ref` - points to a reference-counted object. 52 - * `kmptr_kind_node` - points to a reference-counted object. 53 - 54 53 ### kmcell 55 54 56 55 `kmcell` is a stub struct used to disambiguate between source types.a "source" is an object that can hold an allocated object, such as the heap, a memory pool, a fixed-length array on stack, or a fixed-length global array. all values produced by a kmem allocation function point to within a `kmcell`. 57 56 58 57 * `kmptr_kind kind` - kind of cell 59 58 * `size_t sz` - kind of cell (data plus all fields) 60 59 * `kmshred shred` - shredding flag 61 60 62 61 ### kmref 63 62 64 63 `kmref` is a struct that constitutes the in-memory representation of a reference-counted cell. 65 64 66 - * `kmcell_kind kind = ref` - kind of cell 65 + * `kmkind kind = kmkind_ref` - kind of cell 67 66 * `size_t sz` - size of cell (data plus all fields) 68 67 * `kmshred shred` - shredding flag 69 68 * `size_t refs` - number of active references 70 69 * `kmcell* src` - source, if any 71 70 * `char data[]` - content of cell 72 71 73 72 ### kmnode 74 73 75 74 `kmnode` is a struct that constitutes the in-memory representation of a tree node. 76 75 77 - * `kmcell_kind kind = node` - kind of cell 76 + * `kmkind kind = kmkind_tree` - kind of cell 78 77 * `size_t sz` - size of cell (data plus all fields) 79 78 * `kmshred shred` - shredding flag 80 79 * `kmnode* parent` - parent node 81 80 * `kmnode* child` - first child node 82 81 * `kmnode* lastchild` - last child node 83 82 * `kmnode* prev` - previous sibling, NULL if first 84 83 * `kmnode* next` - next sibling, NULL if last 85 84 * `char data[]` - content of cell 86 85 87 86 ### kmpool 88 87 89 - * `kmcell_kind kind = pool` - indicates the kind of source 88 + * `kmkind kind = kmkind_pool` - indicates the kind of source 90 89 * `size_t sz` - size of cell (data plus all fields) 91 90 * `kmshred shred` - shredding flag 92 91 * `size_t cellsz` - size of individual pool cells 93 92 * `kmpoolcell* top` - pointer to most recently allocated pool cell 94 93 * `kmpoolcell* bottom` - pointer to most recently freed pool cell 95 94 * `kmpoolcell data[]` - content of cell 96 95 97 -### kmpoolcell 96 +#### kmpoolcell 98 97 99 98 * `kmpoolcell* last` - pointer to last element allocated before this one 100 99 * `char data[]` - pool data 101 100 102 101 ### kmshred 103 102 104 103 `kmshred` is an enum used to indicate whether an object should be "shredded" (written over) in memory when it's deleted. this is a useful means to ensure that privileged information is not accidentally left in memory after use. if the shredding mechanism is not useful, compile libk with the flag `KFmem_noshred` to exclude its functions and fields. ................................................................................ 151 150 * `tree` [af] - uses a node-child strategy. when a node is freed, all of its children are automatically freed as well. 152 151 * `kmtreea(kmcell* src, void* parent, size_t) → void*` - create a tree node. if `parent` is NULL, the node will the top of a new tree. if src is null, allocate on-heap. 153 152 * `kmtreez(kmcell* src, void* parent, size_t) → void*` - like `kmtreea` but zeroed 154 153 * `kmtreeao(kmcell* src, void* parent, size_t) → kmptr` - like `kmtreea` but returns a `kmptr` 155 154 * `kmtreezo(kmcell* src, void* parent, size_t) → kmptr` - like `kmtreez` but returns a `kmptr` 156 155 * `kmtreef(void*) → kmptr` - frees a node and all its children 157 156 157 +## macros 158 + 159 +kmem defines the following macros. 160 + 161 + * `Kmsz(array)` - a convenience macro to return the number of elements in a static array. inserts the text `( sizeof (array) / sizeof (array) [0] )`
Added kmem/makefile version [f0df06fe05].
1 +include ../modmake
Added kmem/mem.h version [dc631dc568].
1 +#ifndef KImem 2 +#define KImem 3 + 4 +#endif
Added kmsg/kmsg.md version [1bf7781e05].
1 +# kmsg
Added kmsg/makefile version [f0df06fe05].
1 +include ../modmake
Added kmsg/msg.h version [b69837b00c].
1 +#ifndef KImsg 2 +#define KImsg 3 + 4 +#endif
Added knet/knet.md version [caaca9de66].
1 +# knet
Added knet/makefile version [f0df06fe05].
1 +include ../modmake
Added knet/net.h version [a2f498298b].
1 +#ifndef KInet 2 +#define KInet 3 + 4 +#endif
Added kproc/kproc.md version [ca8b9fab82].
1 +# kproc
Added kproc/makefile version [f0df06fe05].
1 +include ../modmake
Added kproc/proc.h version [8fdd57f87b].
1 +#ifndef KIproc 2 +#define KIproc 3 + 4 +#endif
Added kstr/kstr.md version [8ba3da6088].
1 +# kstr 2 + 3 +**kstr** is the libk string library. it uses the **short** naming convention with the glyph `s`. **kstr** implies `#include <k/mem.h>`. 4 + 5 +## types 6 + 7 +### struct kstr 8 +`struct kstr` is a structure for holding pascal strings (length-prefixed strings). it is the basic libk string type. **note:** if `ptr.ref` ≠ NULL and `sz` = 0, the string's length is unknown and should be calculated by any function that operates on a kstr, storing the result in the object if possible. 9 + * `size_t sz` - length of string, excluding any null terminator 10 + * `kmptr ptr` - pointer to string in memory 11 + 12 +### struct ksraw 13 +`struct ksraw` is like `kstr` except it uses raw `char` pointers instead of a `kmptr`. 14 + * `size_t sz` - length of string, excluding any null terminator 15 + * `char* ptr` - pointer to string in memory 16 + 17 +### struct ksbuf 18 +`struct ksbuf` is a structure used to hold buffers. 19 + * `size_t sz` - maximum size of buffer, including any null terminator 20 + * `char* buf` - region of memory to store buffer in 21 + * `ksalloc strat` - allocation strategy 22 + * `kmkind rule` - kind of allocator to use. only needs to be set if `where` is NULL. see [kmem](../kmem/kmem.md). 23 + * `kmcell* where` - where to allocate the object, in case of pool or tree allocation. 24 + 25 +### struct kschain 26 +`struct kschain` is a structure used for string accumulators that works by aggregating pointers to strings, instead of copying the strings themselves. 27 + * `kschain_kind kind` - kind of chain 28 + * `kmkind rule` - kind of allocation to use if `kind` ≠ `kschain_kind_linked` 29 + * `pstr* ptrs` - pointer to pointer list 30 + * `size_t ptrc` - number of pointers 31 + * `size_t sz` - total amount of space in `ptrs` 32 + 33 +#### enum kschain_kind 34 + * `kschain_kind_block` - occupies a single block of memory 35 + * `kschain_kind_linked` - uses a linked list, allocated and deallocated as necessary 36 + 37 +### enum ksalloc 38 +`enum ksalloc` is an enumerator that tells libk what strategy to use when filling a `ksbuf` or `kschain` struct. 39 + * `ksalloc_static` - do not allocate memory, fill an already-allocated, statically-sized array. 40 + * `ksalloc_alloc` - allocate a string in memory using the specified kind of allocator. 41 + * `ksalloc_dynamic` - fill an already-allocated array if possible, allocate a string in memory if the string length exceeds available space. 42 + 43 +## functions 44 + 45 +### kssz 46 +`size_t kssz(char* str, size_t max)` returns the number of characters in a C string, **including** the final null. will count at most `max` characters if `max` > 0. 47 + 48 +### kstr 49 +`kstr kstr(char* str, size_t max)` takes a C string and returns a P-string, calculating the length of `str` and storing it in the return value. `max` works as in `kssz`. 50 + 51 +### kstoraw 52 +`ksraw ksref(kstr)` is a simple convenience function that returns the `ksraw` form of a `kstr`. 53 + 54 +### kscomp 55 +`char* kscomp(size_t ct, ksraw struct[], kmbuf* buf)` is a **string composition** function. it serves as an efficient, generalized replacement for functions like `strcat` and `strdup`. 56 + 57 +to use kscomp, create an array of `kstr` and fill it with the strings you wish to concatenate. for example, to programmatically generate an HTML link tag, you might use the following code. 58 + 59 + char mem[512]; 60 + kmptr text = <...>; 61 + char* src = <...>; 62 + kmbuf buf = { sizeof mem, &mem, kmkind_none }; 63 + kstr chain[] = { 64 + Kstr("<a href=\""), { 0, src }, Kstr("\">"), 65 + ksref(text), 66 + Kstr("</a>") 67 + }; 68 + char* html = kscomp([Kmsz(chain)](../kmem/kmem.md), chain, &buf); 69 + 70 +kscomp will only calculate the length of individual strings if they are not already known. when it needs to calculate the length of a string, it will store that length in the original array so repeated calls can be made without needing to repeatedly calculate the lengths. this is not always desirable, so the variant `kscompc` exists, which is exactly the same as `kscomp` in every respect except that `chain` is not altered in any way. 71 + 72 +### macros 73 +if `KFclean` is not set when <k/str.h> is included, the following macros are defined. 74 + 75 + * `Kstr(string)` - the compile-time equivalent to `kstr()`. `Kstr` takes a literal string and inserts the text `{ sizeof (string), string }` into the document, suitable for initializing a kstr.
Added kstr/makefile version [f0df06fe05].
1 +include ../modmake
Added kstr/str.h version [21d6720beb].
1 +#ifndef KIstr 2 +#define KIstr 3 + 4 +#endif
Added kterm/kterm.md version [5df0db1632].
1 +# kterm
Added kterm/makefile version [f0df06fe05].
1 +include ../modmake
Added kterm/term.h version [891027d45b].
1 +#ifndef KIterm 2 +#define KIterm 3 + 4 +#endif
Modified libk.md from [4cea7e271a] to [d44feffbdd].
31 31 32 32 libk is designed to fix this (in hindsight) glaring error. 33 33 34 34 however, a common problem with libraries is the proliferation of inordinately long and hard-to-type function names such as `SuperWidget_Widget_Label_Font_Size_Set()`. this may be tolerable in IDEs with robust auto-complete or when referencing a highly-specific, sparsely-used library; it is however completely intolerable in the case of a core library with heavily used functionality. 35 35 36 36 therefore, libk uses two slightly different naming conventions: the **short** convention, for core functions the user will call frequently, and the **full** convention, for less-commonly used functions. the inconvenience of remembering which is which will hopefully be outweighed by the keystrokes (and bytes) saved. 37 37 38 -in the **full** convention, a function's name is prefixed with its module name followed by an underscore. thus, `kfile/open.c` will be invoked as `kfile_open()`. 38 +in the **full** convention, an identifier's name is prefixed with its module name followed by an underscore. thus, `kgraft/list.c` is invoked as `kgraft_list()`. 39 39 40 -in the **short** convention, the function name is prefixed by the letter `k` followed by the module's "glyph" -- a one- or two-letter sequence that represents the module, usually the first one or two characters. therefore, `kio/write.c` is invoked as `kiowrite`. 40 +in the **short** convention, identifiers are prefixed by the letter `k` followed by the module's "glyph" -- a one- or two-letter sequence that represents the module, usually the first one or two characters. therefore, `kfile/open.c` is invoked as `kfopen`. 41 41 42 42 which naming convention a module uses should be specified at the top of its documentation. if it uses the short convention, its glyph should be specified as well 43 43 44 +in both naming conventions, the following rules apply: 45 + 46 + 1. the possible values of enumeration types are always preceded by the name of the enumeration type and an underscore. for instance, the enum `kschain_kind` has a value named `kschain_kind_block`. **exception:** an enum named `<S>_kind`, where `<S>` is a struct type, may simply use the prefix `<S>_`. 47 + 2. macros begin with the uppercase letter `K` -- e.g. `Kmacro`. macros that can be defined by the user to alter the behavior of the api should begin with `KF` if they are on/off flags, or `KV` otherwise. 48 + 3. capital letters are only used in macro prefixes. 49 + 4. low-level function names are prefixed with the API they call into. for example, the function that performs the POSIX syscall `write` is named `kio_posix_fd_write`.a wrapper around the Windows function `CreateProcess()` might be called `kproc_win_createprocess`. 50 + 44 51 ### atoms 45 52 46 53 libk uses the concept of "atoms" (small, regular strings of text) to standardize common references, such as operating systems or processor architectures. 47 54 48 55 #### operating systems 49 56 50 57 these atoms will be used to reference operating systems. ................................................................................ 71 78 72 79 these atoms will be used to reference particular system architectures. these will mostly be used in the filenames of assembly code. 73 80 74 81 ## macros 75 82 76 83 libk will not in any circumstance use macros to encode magic numbers, instead using typedef'd enums. all libk macros begin with the uppercase letter `K` -- e.g. `Kmacro`. macros that can be defined by the user to alter the behavior of the api should begin with `KF` if they are on/off flags, or `KV` otherwise. **macros should only be defined by the libk headers if the flag `KFclean` is *not* defined at the time of inclusion.** 77 84 85 +include guards take the form of the bare module name prefixed by `KI`. so to test if `k/term.h` has been included, you could write `#ifdef KIterm`. 86 + 78 87 ## languages 79 88 80 89 libk uses only three languages: C (\*.c, \*.h), yasm (\*.s), and make (makefile). 81 90 82 91 other assemblers will probably be necessary for the more exotic targets, however. 83 92 84 93 ## repository structure ................................................................................ 90 99 each function should be kept in a separate file within its module's directory. when OS or architecture-specific code is needed, the file's name should be a list of one or more of the fields [arch, OS, bits, format] separated by a `.` -- for instance, the 32-bit x86 haiku version of a function called `write` defined in assembly would be named `write.x86.haiku.32.s`. however, if a function has an extraordinarily large number of versions, they may instead be stored in a folder with the same name as the function. 91 100 92 101 each module should have a header named the same thing as the module except without the `k` prefix. (e.g. the header for `kio` is `kio/io.h`) located in its folder. this is the header that the end-user will be importing, and should handle any user-defined flags to present the API the user has selected. 93 102 94 103 each module directory should contain a makefile that can build that module. see **makefiles** below. all makefiles should be named `makefile` (**not** `Makefile`). 95 104 96 105 each module should contain a markdown file. this file's name should be the name of the parent directory suffixed with `.md`; for instance, `kterm` should contain the file `kterm/kterm.md`. this file should document the module as thoroughly as possible 106 + 107 +each module may contain any number of files of the name `exe.*.c`. this files will be treated as *tools* by the build system and compiled as executables, rather than libraries. they should be compiled to `out/$module.$tool` 97 108 98 109 the repository root and each module may also contain the directory `misc`. this directory may be used to store miscellaneous data such as ABI references, developer discussions, and roadmaps. if the `misc` directory is deleted, this must not affect the library or build system's function in any way - that is, nothing outside a `misc` folder may reference a `misc` folder or anything inside it, including documentation. the `misc` directory should be removed when its contents are no longer needed. in most cases, the repository wiki and forum should be used instead of the `misc` folder. 99 110 100 111 the folder `arch` in the root of the repository contains syscall tables and ABI implementations for various architectures. 101 112 102 113 ## makefiles 103 114 104 115 libk uses `make` as its build system. makefiles should be handwritten. there will be one global makefile in the root of the repository, and one makefile for each module. 105 116 106 117 each rule should be prefixed with ${OUT}, to allow retargeting of the build-dir with the OUT environment variable. this is particularly important since the makefiles chain. 107 118 108 119 the rest is TBD. 109 120 121 +## design principles 122 + 123 +there are four overriding principles that guide the design of libk. 124 + 125 + 1. it should be easy to write code that uses it. 126 + 2. it should be easy to read code that uses it. 127 + 3. the simple, obvious way of using libk should produce the most optimal code. 128 + 4. code that uses libk should be idiomatic C. 129 + 130 +for these reasons, the codebase follows a number of strict rules. 131 + 132 +### booleans are banned 133 +there are a number of reasons for this. 134 + 135 +the first is simply that the boolean type in C is a bit messy and libk headers are intended to import as few extra files as possible. 136 + 137 +the second is that boolean-using code can be hard to read. consider a struct declaration of the form `rule r = { 10, buf, true, false, true }`: the meaning of this declaration is opaque unless you've memorized the structure's definition. 138 + 139 +instead, libk uses enums liberally. so the above might be rewritten as e.g.: 140 + 141 + rule r = { 10, buf, 142 + rule_kind_undialectical, 143 + rule_action_expropriate, 144 + rule_target_bourgeoisie 145 + }; 146 + 147 +this makes code much more legible and has the added benefit of making the definitions easier to expand at a later date if new functionality values is needed without breaking the API or ABI. 148 + 110 149 ## build process 111 150 112 151 libk has a number of targets. all files generated by a `make` invocation will be stored in the folder "out" at the root of the repository. this directory may be deleted entirely to clean the repository. 113 152 114 -**defs** will create the directory `out/k/` and populate it with module header files. the `k/` directory shall be suitable to copy to `/usr/include` or similar. these header files will copied by building the `defs` target of each module's makefile. 153 +**defs** will create the directory `out/k/` and populate it with module header files. the `k/` directory shall be suitable to copy to `/usr/include` or similar. these header files will copied by building the `${OUT}/$(module).h` target of each module's makefile. 115 154 116 155 **libk.so** will build the dynamically linked form of libk, according to the build variables set 117 156 118 157 **libk.a** will build the statically linked form of libk, according to the build variables set 119 158 120 159 **tool** will build the executables used for modules such as `kgraft`. 121 160
Modified makefile from [75ffd11290] to [e2aa0ec204].
1 -export OUT=$(PWD)/out 2 -export TARGET=x86.lin.64 1 +export OUT = $(PWD)/out 2 + 3 +export ARCH = x86 4 +export OS = lin 5 +export BITS = 64 6 + 7 +export TARGET = $(ARCH).$(OS).$(BITS) 8 + 9 +moddirs = $(wildcard k*) 10 +modules = $(moddirs:k%=%) 11 +headers = $(moddirs:k%=$(OUT)/k/%.h) 12 +objects = $(modules:%=$(OUT)/k%.o) 13 +makefiles = $(moddirs:%=%/makefile) 14 + 15 +binaries = $(wildcard */exe.*.c) 16 +binmods = $(sort $(dir $(binaries))) 17 + 18 +all: obj defs tool 19 +obj: $(moddirs:%=%.obj) 20 +defs: $(headers) 21 +tool: $(binmods:%=%.tool) 22 + 23 +lists = moddirs modules headers objects makefiles binaries binmods 24 +dbg: 25 + @echo -e lists: $(foreach var, $(lists), "\\n - \\e[1m$(var)\\e[m = $($(var))") 26 + 27 +%.obj: %/makefile $(OUT) 28 + cd $* && $(MAKE) obj 29 + 30 +%.tool: %/makefile $(OUT) 31 + cd $* && $(MAKE) tool 32 + 33 +%.dbg: %/makefile $(OUT) 34 + cd $* && $(MAKE) dbg 35 + 36 +$(OUT)/libk.so: mods $(OUT) 37 + $(CC) -shared -o $@ $(objects) 38 + 39 +$(OUT)/libk.a: mods $(OUT) 40 + # using `ar c` and ranlib here instead of 41 + # `ar cs` in case `ar` isn't the GNU version 42 + ar c $@ $(objects) 43 + ranlib $@ 3 44 4 -all: kio 45 +$(OUT)/k/%.h: k%/makefile $(OUT)/k 46 + cd k$* && $(MAKE) $@ 5 47 6 -$(OUT)/kio.o: 7 - cd kio && make kio 48 +$(OUT) $(OUT)/k: 49 + mkdir -p $@
Added modmake version [247b2f15bf].
1 +#- modmake 2 +# this is the master makefile that controls the building of each 3 +# libk module. it is included from each k*/makefile. 4 +# vim: ft=make 5 + 6 +mod = $(notdir $(PWD)) 7 +src = $(wildcard *.c) $(wildcard *.s) 8 +bare = $(mod:k%=%) 9 + 10 +tools = $(filter exe.%.c, $(src)) 11 +nontools = $(filter-out exe.%.c, $(src)) 12 +cobjects = $(filter %.c, $(nontools)) 13 +sobjects = $(filter %.${TARGET}.s, $(nontools)) 14 + 15 +obj: $(cobjects:%.c=${OUT}/$(mod).%.o) \ 16 + $(sobjects:%.s=${OUT}/$(mod).%.o) 17 +tool: $(tools:exe.%.c=${OUT}/$(mod).%) 18 + 19 +dbg: 20 + @echo tools = $(tools) 21 + @echo TARGET = ${TARGET} 22 + @echo cobjects = $(cobjects) 23 + @echo sobjects = $(sobjects) 24 + @echo mod = $(mod) 25 + 26 +${OUT}/$(mod).%.o: %.c 27 + $(CC) -c $< -o $@ 28 + 29 +${OUT}/k/$(bare).h: $(bare).h 30 + cp $< $@ 31 + 32 +${OUT}/$(mod).%: exe.%.c 33 + $(CC) $< -o $@ 34 + 35 +#- assembly 36 +# compiling the assembly code will be faster but a lot more 37 +# complex, given the nature of assembly and the large number of 38 +# platforms targeted. we need to add build rules for every 39 +# arch.OS[.bits] tuple; since this is a fairly repetetive task 40 +# that requires ugly make rules, we're just going to use a 41 +# function to generate these. 42 + 43 +# ${OUT} = ultimate build directory 44 +# $(mod) = module name 45 +# % = function name 46 +# $(1) = arch tuple 47 +arch = ${OUT}/$(mod).%.$(1).o: %.$(1).s 48 +# invoke with $(call arch,tuple). do not 49 +# put spaces between either term though! 50 + 51 +#-- linux 52 +# linux uses the ELF{32,64} binary format, and generating these 53 +# from yasm is trivial. linux only supports one ABI per format, 54 +# at least with ELF, so that's all we need to do. 55 + 56 +#${OUT}/$(mod).%.x86.lin.32.o: %.x86.lin.32.s 57 +$(call arch,x86.lin.32) 58 + yasm -felf32 $< -o $@ 59 + 60 +#${OUT}/$(mod).%.x86.lin.64.o: %.x86.lin.64.s 61 +$(call arch,x86.lin.64) 62 + yasm -felf64 $< -o $@ 63 + 64 +#-- freebsd 65 +# the freebsd ABI is different, so it will require different code 66 +# (though there might be ways to minimize that). freebsd uses the 67 +# same binary format as Linux (though it also supports a.out and 68 +# COFF) but because freebsd can interpret multiple different ABIs 69 +# the object files need to be "branded" with the correct one 70 +# using the tool brandelf (`brandelf -t [ABI]`) 71 + 72 +$(call arch,x86.fbsd.32) 73 + yasm -felf32 $< -o $@ 74 + brandelf -t FreeBSD $@ 75 + 76 +$(call arch,x86.fbsd.64) 77 + yasm -felf64 $< -o $@ 78 + brandelf -t FreeBSD $@ 79 +