diff --git a/README.md b/README.md index 276548c..8226907 100644 --- a/README.md +++ b/README.md @@ -62,12 +62,12 @@ In this book we will use the ARM LINUX conventions. This means: hope to add a chapter detailing the Windows calling convention. You'll notice right away that we make use of the C-runtime directly -rather than make OS service calls. So, for instance, if we want to -call `write()`, we call `write` from the assembly language. This -version of the system call `write` is a wrapper function built into -the C-runtime which handles the low level details of performing a -system call. See the [chapter](./not_written_yet.md) on what actually -happens inside these wrapper functions. +rather than make OS service calls. So, for instance, if we want to call +`write()`, we call `write` from the assembly language. This version of +the system call `write` is a wrapper function built into the C-runtime +which handles the low level details of performing a system call. See the +[here](./more/system_calls/README.md) on what actually happens inside +these wrapper functions. ## A Lot of Names @@ -217,7 +217,7 @@ knowledge - how cool is that! | 6 | Functions | | | .... a | [.... Calling and Returning](./section_1/funcs/README.md) | NA | | .... b | [.... Passing Parameters](./section_1/funcs/README2.md) | NA | -| .... c | [.... Calling common C runtime functions](./section_1/funcs/README3.md) | NA | +| .... c | [.... Example of calling some common C runtime functions](./section_1/funcs/README3.md) | NA | | 7 | [FizzBuzz - a Complete Program](./section_1/fizzbuzz/README.md) | NA | | 8 | Structs | | | .... a | [.... Alignment](./section_1/structs/alignment.md) | NA | @@ -261,6 +261,7 @@ What would a book about assembly language be without bit bashing? | Chapter | Markdown | PDF | | ------- | -------- | --- | | --- | [Determining string literal lengths for C functions](./more/strlen_for_c/README.md) | NA | +| --- | [Under the hood: System Calls](./more/system_calls/README.md) | NA | ## Projects diff --git a/more/system_calls/README.md b/more/system_calls/README.md new file mode 100644 index 0000000..c9bbf69 --- /dev/null +++ b/more/system_calls/README.md @@ -0,0 +1,178 @@ +# Under the hood: System Calls + +The term "function" is used many places in this book and needs no +additional explanation here. The term "system call" has also been used +in many places, often with a comment that making a system call through +the C runtime is actually just calling an ordinary function acting as +a wrapper. An explanation of this has been promised... + +## Wrappers + +"Wrapper" is a term used to describe a function which hides the details +of something else, often another function or functions. Hiding details +is a form of abstraction and can be a good thing. Broadly speaking, +an API (Application Programmer's Interface) is itself another example +of wrappers in common use. + +## C runtime as a wrapper + +Many C runtime functions are just wrappers for system calls. For example +if you call `open()` from the C runtime, the function will perform a few +bookkeeping operations and then make the actual system call. + +## What IS a system call? + +The short answer is a system call is a sort-of function call that is +serviced by the operating system itself, within its own private region +of memory and with access to internal features and data structures. + +Our programs run in "userland". The technical name for userland on the +ARM64 processor is EL0 (Exception Level 0). + +We can operate within the kernel's space only through carefully +controlled mechanisms - such as system calls. The technical name for +where the kernel (or system) generally operates is called EL1. + +There are two higher Exception Levels (EL2 and EL3) which are beyond +the scope of this book. + +## Mechanism of making a system call + +First, like any function call, parameters need to be set up. The first +parameter goes in the first register, etc. + +Second, a number associated with the specific system call we wish to +make is loaded in a specific register (`w8`). + +Finally, a special instruction `svc` causes a trap which elevates us out +of userland into kernel space. Said differently, `svc` causes a +transition from EL0 to EL1. There, various checks are done and the +actual code for the system call is run. + +A description of returning from a system call is beyond the scope of +this book. Hint: just as there's a special instruction that escalates +from EL0 to EL1, there is a special instruction that does the reverse. + +## What is the number associated with a particular system call? + +Hard question. + +In a perfect world, each Linux distribution would use the same set of +system call numbers. But no. + +[This](https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html) +is he most comprehensive list of system call numbers we have seen. It +shows system call numbers for many architectures and distributions. + +## Example: calling `getpid()` + +The system call `getpid()` fetches the running process's process ID. +Every executing entity has one. + +We present four different versions of the same program: + +1. Written in C++ + +2. Written in C + +3. Written using C runtime from assembly language + +4. Calling the system call directly from assembly language + +### Written in C++ + +```c++ +#include // 1 +#include // 2 + // 3 +using std::cout; // 4 +using std::endl; // 5 + // 6 +int main() { // 7 + cout << "Greetings from: " << getpid() << endl; // 8 + return 0; // 9 +} // 10 +``` + +### Written in C + +```c +#include // 1 +#include // 2 + // 3 +int main() { // 4 + printf("Greetings from: %d\n", getpid()); // 5 + return 0; // 6 +} // 7 +``` + +### Written in assembly language using C runtime + +```text + .global main // 1 + .text // 2 + .align 2 // 3 + // 4 +main: stp x29, x30, [sp, -16]! // 5 + bl getpid // 6 + mov w1, w0 // 7 + ldr x0, =fmt // 8 + bl printf // 9 + ldp x29, x30, [sp], 16 // 10 + mov w0, wzr // 11 + ret // 12 + // 13 + .data // 14 +fmt: .asciz "Greetings from: %d\n" // 15 + // 16 + .end // 17 +``` + +### And finally: calling the system call directly + +```text + .global main // 1 + .text // 2 + .align 2 // 3 + // 4 +main: stp x29, x30, [sp, -16]! // 5 + mov x8, 172 // getpid on ARM64 // 6 + svc 0 // trap to EL1 // 7 + mov w1, w0 // 8 + ldr x0, =fmt // 9 + bl printf // 10 + ldp x29, x30, [sp], 16 // 11 + mov w0, wzr // 12 + ret // 13 + // 14 + .data // 15 +fmt: .asciz "Greetings from: %d\n" // 16 + // 17 + .end // 18 +``` + +We chose `getpid()` because it doesn't require any parameters. Using +the C runtime, we simply `bl` to it. Calling the system call directly +is different in that we must first load `x8` with the number that +corresponds to `getpid()` for the AARCH64 architecture. + +Consulting [this](https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html) +awesome website, we find that the number we want is 172. + +![here](./getpid/getpid.png) + +The constant specific to the system call we want is loaded into `x8`. +Recall that `x0` through `x7` are scratch registers. + +Then on line 7, the `svc` with the argument 0 initiates the escalation +from EL0 to EL1 where the kernel implements our desired functionality +and returns to us. + +### Review + +System calls are functions implemented inside the operating system. + +To get there, at some point perhaps behind a wrapper function, a +specific system call number is placed in `x8` with other scratch +registers getting the system call's documented parameters and the `svc` +instruction is executed. diff --git a/more/system_calls/getpid/getpid.png b/more/system_calls/getpid/getpid.png new file mode 100644 index 0000000..1cb7c80 Binary files /dev/null and b/more/system_calls/getpid/getpid.png differ diff --git a/more/system_calls/getpid/main.c b/more/system_calls/getpid/main.c new file mode 100644 index 0000000..df1ba8f --- /dev/null +++ b/more/system_calls/getpid/main.c @@ -0,0 +1,7 @@ +#include +#include + +int main() { + printf("Greetings from: %d\n", getpid()); + return 0; +} diff --git a/more/system_calls/getpid/main.cpp b/more/system_calls/getpid/main.cpp new file mode 100644 index 0000000..d869f9c --- /dev/null +++ b/more/system_calls/getpid/main.cpp @@ -0,0 +1,10 @@ +#include +#include + +using std::cout; +using std::endl; + +int main() { + cout << "Greetings from: " << getpid() << endl; + return 0; +} \ No newline at end of file diff --git a/more/system_calls/getpid/main_asm.s b/more/system_calls/getpid/main_asm.s new file mode 100644 index 0000000..d1e53ab --- /dev/null +++ b/more/system_calls/getpid/main_asm.s @@ -0,0 +1,17 @@ + .global main + .text + .align 2 + +main: stp x29, x30, [sp, -16]! + bl getpid + mov w1, w0 + ldr x0, =fmt + bl printf + ldp x29, x30, [sp], 16 + mov w0, wzr + ret + + .data +fmt: .asciz "Greetings from: %d\n" + + .end diff --git a/more/system_calls/getpid/main_direct.s b/more/system_calls/getpid/main_direct.s new file mode 100644 index 0000000..beb8e64 --- /dev/null +++ b/more/system_calls/getpid/main_direct.s @@ -0,0 +1,18 @@ + .global main + .text + .align 2 + +main: stp x29, x30, [sp, -16]! + mov x8, 172 // getpid on ARM64 + svc 0 // trap to EL1 + mov w1, w0 + ldr x0, =fmt + bl printf + ldp x29, x30, [sp], 16 + mov w0, wzr + ret + + .data +fmt: .asciz "Greetings from: %d\n" + + .end diff --git a/section_1/funcs/README3.md b/section_1/funcs/README3.md index 17eb629..d4c94e4 100644 --- a/section_1/funcs/README3.md +++ b/section_1/funcs/README3.md @@ -1,9 +1,57 @@ -# Section 1 / Examples of calling common C runtime functions +# Section 1 / Example of calling some common C runtime functions -This chapter gives examples of calling common C runtime functions from -assembly language. +This chapter gives an example of calling the most common C I/O functions + from assembly language. + +There are, by the way, two broad types of functions within the C +runtime. Some are implemented largely in the C runtime itself. Others +that exist in the C runtime act as wrappers for functions implemented +within the OS itself. These are called "system calls". + +For the purposes of calling functions in the C runtime, there is no +practical difference between these two types. Note however, there are +ways of calling system calls directly using the `svc` instruction. We +will cover this way of making system calls as well. See +[here](../../more/system_calls/README.md). ## Low level file operations -The following example shows `open()`, `close()`, `read()`, `write()` -and `lseek()`. +This example [program](./file_ops.s) makes use of `open()`, `close()`, +`read()`, `write()` and `lseek()`. These are implemented in the C +runtime as wrappers for system calls. + +The program will + +* create a file, + +* write a small amount of text to it, + +* rewind (seek) back to the beginning of the file, + +* read back and print the contents of the file and then + +* close the file. + +A lot of error checking is also implemented (frankly speaking: until we +got bored writing the example). + +Doing all of these ballooned the example program to about 200 lines. As +such we won't explain the code line by line but, in compensation, the +code is liberally commented. + +Here is just a bit: + +```text +/* off_t lseek(int fd, off_t offset, int whence); +*/ +seek_zero: + stp x29, x30, [sp, -16]! + mov w0, fd // file descriptor + mov x1, xzr // beginning of file + mov w2, wzr // SEEK_SET - absolute offset + bl lseek + ldp x29, x30, [sp], 16 + ret +``` + +Calling this function rewinds the read / write "head" to position 0. diff --git a/section_1/funcs/fo.s b/section_1/funcs/fo.s deleted file mode 100644 index 1d120d0..0000000 --- a/section_1/funcs/fo.s +++ /dev/null @@ -1,313 +0,0 @@ - .arch armv8-a - .file "fo.cpp" - .text - .section .text._ZStanSt13_Ios_FmtflagsS_,"axG",@progbits,_ZStanSt13_Ios_FmtflagsS_,comdat - .align 2 - .weak _ZStanSt13_Ios_FmtflagsS_ - .type _ZStanSt13_Ios_FmtflagsS_, %function -_ZStanSt13_Ios_FmtflagsS_: -.LFB1316: - .cfi_startproc - sub sp, sp, #16 - .cfi_def_cfa_offset 16 - str w0, [sp, 12] - str w1, [sp, 8] - ldr w1, [sp, 12] - ldr w0, [sp, 8] - and w0, w1, w0 - add sp, sp, 16 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE1316: - .size _ZStanSt13_Ios_FmtflagsS_, .-_ZStanSt13_Ios_FmtflagsS_ - .section .text._ZStorSt13_Ios_FmtflagsS_,"axG",@progbits,_ZStorSt13_Ios_FmtflagsS_,comdat - .align 2 - .weak _ZStorSt13_Ios_FmtflagsS_ - .type _ZStorSt13_Ios_FmtflagsS_, %function -_ZStorSt13_Ios_FmtflagsS_: -.LFB1317: - .cfi_startproc - sub sp, sp, #16 - .cfi_def_cfa_offset 16 - str w0, [sp, 12] - str w1, [sp, 8] - ldr w1, [sp, 12] - ldr w0, [sp, 8] - orr w0, w1, w0 - add sp, sp, 16 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE1317: - .size _ZStorSt13_Ios_FmtflagsS_, .-_ZStorSt13_Ios_FmtflagsS_ - .section .text._ZStcoSt13_Ios_Fmtflags,"axG",@progbits,_ZStcoSt13_Ios_Fmtflags,comdat - .align 2 - .weak _ZStcoSt13_Ios_Fmtflags - .type _ZStcoSt13_Ios_Fmtflags, %function -_ZStcoSt13_Ios_Fmtflags: -.LFB1319: - .cfi_startproc - sub sp, sp, #16 - .cfi_def_cfa_offset 16 - str w0, [sp, 12] - ldr w0, [sp, 12] - mvn w0, w0 - add sp, sp, 16 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE1319: - .size _ZStcoSt13_Ios_Fmtflags, .-_ZStcoSt13_Ios_Fmtflags - .section .text._ZStoRRSt13_Ios_FmtflagsS_,"axG",@progbits,_ZStoRRSt13_Ios_FmtflagsS_,comdat - .align 2 - .weak _ZStoRRSt13_Ios_FmtflagsS_ - .type _ZStoRRSt13_Ios_FmtflagsS_, %function -_ZStoRRSt13_Ios_FmtflagsS_: -.LFB1320: - .cfi_startproc - stp x29, x30, [sp, -32]! - .cfi_def_cfa_offset 32 - .cfi_offset 29, -32 - .cfi_offset 30, -24 - mov x29, sp - str x0, [sp, 24] - str w1, [sp, 20] - ldr x0, [sp, 24] - ldr w0, [x0] - ldr w1, [sp, 20] - bl _ZStorSt13_Ios_FmtflagsS_ - mov w1, w0 - ldr x0, [sp, 24] - str w1, [x0] - ldr x0, [sp, 24] - ldp x29, x30, [sp], 32 - .cfi_restore 30 - .cfi_restore 29 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE1320: - .size _ZStoRRSt13_Ios_FmtflagsS_, .-_ZStoRRSt13_Ios_FmtflagsS_ - .section .text._ZStaNRSt13_Ios_FmtflagsS_,"axG",@progbits,_ZStaNRSt13_Ios_FmtflagsS_,comdat - .align 2 - .weak _ZStaNRSt13_Ios_FmtflagsS_ - .type _ZStaNRSt13_Ios_FmtflagsS_, %function -_ZStaNRSt13_Ios_FmtflagsS_: -.LFB1321: - .cfi_startproc - stp x29, x30, [sp, -32]! - .cfi_def_cfa_offset 32 - .cfi_offset 29, -32 - .cfi_offset 30, -24 - mov x29, sp - str x0, [sp, 24] - str w1, [sp, 20] - ldr x0, [sp, 24] - ldr w0, [x0] - ldr w1, [sp, 20] - bl _ZStanSt13_Ios_FmtflagsS_ - mov w1, w0 - ldr x0, [sp, 24] - str w1, [x0] - ldr x0, [sp, 24] - ldp x29, x30, [sp], 32 - .cfi_restore 30 - .cfi_restore 29 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE1321: - .size _ZStaNRSt13_Ios_FmtflagsS_, .-_ZStaNRSt13_Ios_FmtflagsS_ - .section .text._ZNSt8ios_base4setfESt13_Ios_FmtflagsS0_,"axG",@progbits,_ZNSt8ios_base4setfESt13_Ios_FmtflagsS0_,comdat - .align 2 - .weak _ZNSt8ios_base4setfESt13_Ios_FmtflagsS0_ - .type _ZNSt8ios_base4setfESt13_Ios_FmtflagsS0_, %function -_ZNSt8ios_base4setfESt13_Ios_FmtflagsS0_: -.LFB1350: - .cfi_startproc - stp x29, x30, [sp, -48]! - .cfi_def_cfa_offset 48 - .cfi_offset 29, -48 - .cfi_offset 30, -40 - mov x29, sp - str x0, [sp, 24] - str w1, [sp, 20] - str w2, [sp, 16] - ldr x0, [sp, 24] - ldr w0, [x0, 24] - str w0, [sp, 44] - ldr w0, [sp, 16] - bl _ZStcoSt13_Ios_Fmtflags - mov w1, w0 - ldr x0, [sp, 24] - add x0, x0, 24 - bl _ZStaNRSt13_Ios_FmtflagsS_ - ldr w1, [sp, 16] - ldr w0, [sp, 20] - bl _ZStanSt13_Ios_FmtflagsS_ - mov w1, w0 - ldr x0, [sp, 24] - add x0, x0, 24 - bl _ZStoRRSt13_Ios_FmtflagsS_ - ldr w0, [sp, 44] - ldp x29, x30, [sp], 48 - .cfi_restore 30 - .cfi_restore 29 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE1350: - .size _ZNSt8ios_base4setfESt13_Ios_FmtflagsS0_, .-_ZNSt8ios_base4setfESt13_Ios_FmtflagsS0_ - .section .text._ZSt3hexRSt8ios_base,"axG",@progbits,_ZSt3hexRSt8ios_base,comdat - .align 2 - .weak _ZSt3hexRSt8ios_base - .type _ZSt3hexRSt8ios_base, %function -_ZSt3hexRSt8ios_base: -.LFB1378: - .cfi_startproc - stp x29, x30, [sp, -32]! - .cfi_def_cfa_offset 32 - .cfi_offset 29, -32 - .cfi_offset 30, -24 - mov x29, sp - str x0, [sp, 24] - mov w2, 74 - mov w1, 8 - ldr x0, [sp, 24] - bl _ZNSt8ios_base4setfESt13_Ios_FmtflagsS0_ - ldr x0, [sp, 24] - ldp x29, x30, [sp], 32 - .cfi_restore 30 - .cfi_restore 29 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE1378: - .size _ZSt3hexRSt8ios_base, .-_ZSt3hexRSt8ios_base - .local _ZStL8__ioinit - .comm _ZStL8__ioinit,1,8 - .section .rodata - .align 3 -.LC0: - .string "test.txt" - .text - .align 2 - .global main - .type main, %function -main: -.LFB1729: - .cfi_startproc - stp x29, x30, [sp, -32]! - .cfi_def_cfa_offset 32 - .cfi_offset 29, -32 - .cfi_offset 30, -24 - mov x29, sp - mov w2, 438 - mov w1, 66 - adrp x0, .LC0 - add x0, x0, :lo12:.LC0 - bl open - str w0, [sp, 28] - ldr w1, [sp, 28] - adrp x0, :got:_ZSt4cout - ldr x0, [x0, #:got_lo12:_ZSt4cout] - bl _ZNSolsEi - mov x2, x0 - adrp x0, :got:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ - ldr x1, [x0, #:got_lo12:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_] - mov x0, x2 - bl _ZNSolsEPFRSoS_E - adrp x0, _ZSt3hexRSt8ios_base - add x1, x0, :lo12:_ZSt3hexRSt8ios_base - adrp x0, :got:_ZSt4cout - ldr x0, [x0, #:got_lo12:_ZSt4cout] - bl _ZNSolsEPFRSt8ios_baseS0_E - mov w1, 66 - bl _ZNSolsEi - mov x2, x0 - adrp x0, :got:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ - ldr x1, [x0, #:got_lo12:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_] - mov x0, x2 - bl _ZNSolsEPFRSoS_E - ldr w0, [sp, 28] - cmp w0, 0 - blt .L16 - ldr w0, [sp, 28] - bl close -.L16: - mov w0, 0 - ldp x29, x30, [sp], 32 - .cfi_restore 30 - .cfi_restore 29 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE1729: - .size main, .-main - .align 2 - .type _Z41__static_initialization_and_destruction_0ii, %function -_Z41__static_initialization_and_destruction_0ii: -.LFB2230: - .cfi_startproc - stp x29, x30, [sp, -32]! - .cfi_def_cfa_offset 32 - .cfi_offset 29, -32 - .cfi_offset 30, -24 - mov x29, sp - str w0, [sp, 28] - str w1, [sp, 24] - ldr w0, [sp, 28] - cmp w0, 1 - bne .L20 - ldr w1, [sp, 24] - mov w0, 65535 - cmp w1, w0 - bne .L20 - adrp x0, _ZStL8__ioinit - add x0, x0, :lo12:_ZStL8__ioinit - bl _ZNSt8ios_base4InitC1Ev - adrp x0, __dso_handle - add x2, x0, :lo12:__dso_handle - adrp x0, _ZStL8__ioinit - add x1, x0, :lo12:_ZStL8__ioinit - adrp x0, :got:_ZNSt8ios_base4InitD1Ev - ldr x0, [x0, #:got_lo12:_ZNSt8ios_base4InitD1Ev] - bl __cxa_atexit -.L20: - nop - ldp x29, x30, [sp], 32 - .cfi_restore 30 - .cfi_restore 29 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE2230: - .size _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii - .align 2 - .type _GLOBAL__sub_I_main, %function -_GLOBAL__sub_I_main: -.LFB2231: - .cfi_startproc - stp x29, x30, [sp, -16]! - .cfi_def_cfa_offset 16 - .cfi_offset 29, -16 - .cfi_offset 30, -8 - mov x29, sp - mov w1, 65535 - mov w0, 1 - bl _Z41__static_initialization_and_destruction_0ii - ldp x29, x30, [sp], 16 - .cfi_restore 30 - .cfi_restore 29 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE2231: - .size _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main - .section .init_array,"aw" - .align 3 - .xword _GLOBAL__sub_I_main - .hidden __dso_handle - .ident "GCC: (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0" - .section .note.GNU-stack,"",@progbits diff --git a/section_1/funcs/seek.c b/section_1/funcs/seek.c new file mode 100644 index 0000000..6a46d21 --- /dev/null +++ b/section_1/funcs/seek.c @@ -0,0 +1,6 @@ +#include + +void Foo() { + write(0, 0, 0); + return; +} \ No newline at end of file diff --git a/section_1/funcs/seek.s b/section_1/funcs/seek.s new file mode 100644 index 0000000..536c21d --- /dev/null +++ b/section_1/funcs/seek.s @@ -0,0 +1,21 @@ + .section __TEXT,__text,regular,pure_instructions + .build_version macos, 13, 0 sdk_version 13, 1 + .globl _Foo ; -- Begin function Foo + .p2align 2 +_Foo: ; @Foo + .cfi_startproc +; %bb.0: + stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill + mov x29, sp + .cfi_def_cfa w29, 16 + .cfi_offset w30, -8 + .cfi_offset w29, -16 + mov w0, #0 + mov x1, #0 + mov x2, #0 + bl _write + ldp x29, x30, [sp], #16 ; 16-byte Folded Reload + ret + .cfi_endproc + ; -- End function +.subsections_via_symbols diff --git a/section_1/funcs/test.txt b/section_1/funcs/test.txt new file mode 100644 index 0000000..4268632 --- /dev/null +++ b/section_1/funcs/test.txt @@ -0,0 +1 @@ +some data diff --git a/section_3/endian/README.md b/section_3/endian/README.md index 1bd1b32..39de9c4 100644 --- a/section_3/endian/README.md +++ b/section_3/endian/README.md @@ -13,27 +13,24 @@ The TL;DR of endianness is this: * suppose you have a pointer to a `short` -* is the *byte* at the address contained in the pointer the first byte +* is the byte at the address contained in the pointer the first byte of the `short` or the second? -* this extends to `int` and to `long` as well - -That's the essential nugget. +This extends to `int` and to `long` as well. ## Why talk about this? Endianness is mostly hidden from you. The value of an `int` is the value -you think it is and how the `int` is constructed isn't even on your +you think it is and how the `int` is constructed probably isn't on your radar. Endianness is a big deal for people who code network applications where -early on a standard was required to determine which byte of an `int` is +early on, a standard was required to determine which byte of an `int` is the first one transmitted over the wire. Network Byte Order is big -endian. Unfortunately, most of todays very popular processors are -little endian. +endian. Most of todays very popular processors are little endian. -For us assembly language coders, endianness comes into play when we're -using our debuggers. After all, when we examine memory, memory is a +For us assembly language coders, endianness especially comes into play +when we're using our debuggers. When we examine memory, memory is a linear stream of bytes. Without understanding endianness, you might be confused about what you're seeing. @@ -48,8 +45,10 @@ end. Please read the entirety of Gulliver's Travels keeping in mind how absolutely nasty Swift's portrayal of 18th century politics can be. You -won't be disappointed. And no, the classic cartoon version, Max -Fleischer's 1939 masterpiece, doesn't do the book justice. +won't be disappointed. + +The classic cartoon version, Max Fleischer's 1939 masterpiece, doesn't +do the book justice. ## How do the terms apply? @@ -59,7 +58,7 @@ significant byte lives. Thus the terms... If the most significant byte comes first, the architecture is said to be big-endian. If the least significant byte comes first, it is little -endian. +endian. There's a little more to it than that, but not much. **Notice I have not discussed strings.** @@ -122,17 +121,17 @@ string Dump(T & i) { // 15 } // 24 ``` -First, you might not be familiar with templated functions. Notice -line 14 tells the compiler that the next function is templated and that -`T` be take on the value matching the parameter that is actually given -to the function. +You might not be familiar with templated functions. Notice line 14 tells +the compiler that the next function is templated and that `T` will stand +in for the type matching the parameter that is actually given to the +function. -Thus, at compile time, the compiler write a different function for each +Thus, at compile time, the compiler writes a different function for each of `int`, `short` and `long`. When the compiler gets to the `sizeof()` on line 20, the size of the "right" type is taken. -Using the templated approach we need write this function only once -rather than three times for each of `int`, `short` and `long`. +Using the templated approach, we need write this function only once +rather than three times (for each of `int`, `short` and `long`). ## Output on a little endian machine @@ -169,6 +168,7 @@ i64: 89abcdef01234567 ``` Notice the values for `i16` and `i32` match the right hand column above. + The value for `i64` is borked in that we specified it in the C code as a `long`. We then tried specifying the `long` as a `long long`. Apparently there is little support for 64 bit numbers on this ancient but