diff --git a/section_1/structs/defining.md b/section_1/structs/defining.md new file mode 100644 index 0000000..3fd9322 --- /dev/null +++ b/section_1/structs/defining.md @@ -0,0 +1,121 @@ +# Section 1 / Defining `structs` + +Given: + +```c +struct Foo { + short a; + char b; + int c; +}; + +struct Foo Bar = { 0xaaaa, 0xbb, 0xcccccccc }; +``` + +Here is [one](./test02_companion1.s) way of defining and accessing the struct: + +```text + .global main // 1 + .text // 2 + .align 2 // 3 + // 4 +main: // 5 + str x30, [sp, 16]! // 6 + // 7 + ldr x0, =fmt // 8 + ldr x1, =Bar // 9 + ldrh w2, [x1] // 10 + ldrb w3, [x1, 2] // 11 + ldr w4, [x1, 4] // 12 + bl printf // 13 + // 14 + ldr x30, [sp], 16 // 15 + mov w0, wzr // 16 + ret // 17 + // 18 + .data // 19 + // 20 +fmt: .asciz "%p a: 0x%x b: 0x%x c: 0x%x\n" // 21 +``` + +It would be understandable if you don't see where the `struct` is being +defined. That's because it isn't. Rather, the implied +0 on `line 10` and +the 2 and 4 on `lines 11` and `12` are the hard coded offsets into the +`struct`. + +[Here](./test02_companion2.s) is a second way to define a `struct`. + +```text + .global main // 1 + .text // 2 + .align 2 // 3 + // 4 + .equ foo_a, 0 # like #define // 5 + .equ foo_b, 2 # like #define // 6 + .equ foo_c, 4 # like #define // 7 + // 8 +main: // 9 + str x30, [sp, 16]! // 10 + // 11 + ldr x0, =fmt // 12 + ldr x1, =Bar // 13 + ldrh w2, [x1, foo_a] // 14 + ldrb w3, [x1, foo_b] // 15 + ldr w4, [x1, foo_c] // 16 + bl printf // 17 + // 18 + ldr x30, [sp], 16 // 19 + mov w0, wzr // 20 + ret // 21 + // 22 + .data // 23 + // 24 +fmt: .asciz "%p a: 0x%x b: 0x%x c: 0x%x\n" // 25 +``` + +This method uses `.equ` to make the offsets into symbolic constants. +This is just like using `#define` in C and C++. That is, the above is +equivalent to the following in C or C++: + +```c +#define foo_a 0 +#define foo_b 2 +#define foo_c 4 +``` + +Finally, [here](./test02_companion3.s) is a third way of defining `structs`. + +```text + .global main // 1 + .text // 2 + .align 2 // 3 + // 4 +main: // 5 + str x30, [sp, 16]! // 6 + // 7 + ldr x0, =fmt // 8 + ldr x1, =Bar // 9 + ldrh w2, [x1, Foo.a] // 10 + ldrb w3, [x1, Foo.b] // 11 + ldr w4, [x1, Foo.c] // 12 + bl printf // 13 + // 14 + ldr x30, [sp], 16 // 15 + mov w0, wzr // 16 + ret // 17 + // 18 + .section Foo // 19 + .struct 0 // a starts at 0 and goes for 2 // 20 +Foo.a: .struct Foo.a + 2 // b starts at 2 and goes for 2 // 21 +Foo.b: .struct Foo.b + 2 // c starts at 4 // 22 +Foo.c: // 23 + // 24 + .data // 25 + // 26 +fmt: .asciz "%p a: 0x%x b: 0x%x c: 0x%x\n" // 27 +``` + +We aren't sure this method has anything to commend it over the previous +method other than it does emphasize that offsets are relative to the +data member that comes before it. + diff --git a/section_1/structs/test01.c b/section_1/structs/test01.c index fea2f3e..2ff8cdd 100644 --- a/section_1/structs/test01.c +++ b/section_1/structs/test01.c @@ -1,7 +1,7 @@ struct Foo { - long a; - short b; - int c; + long a; + short b; + int c; }; struct Foo Bar = { 0xaaaaaaaaaaaaaaaa, 0xbbbb, 0xcccccccc }; diff --git a/section_1/structs/test01_companion1.s b/section_1/structs/test01_companion1.s new file mode 100644 index 0000000..a29fb6b --- /dev/null +++ b/section_1/structs/test01_companion1.s @@ -0,0 +1,21 @@ + .global main + .text + .align 2 + +main: + str x30, [sp, 16]! + + ldr x0, =fmt + ldr x1, =Fee + ldr x2, [x1] + ldrh w3, [x1, 8] + ldr w4, [x1, 12] + bl printf + + ldr x30, [sp], 16 + mov w0, wzr + ret + + .data + +fmt: .asciz "%p a: 0x%lx b: %x c: %x\n" diff --git a/section_1/structs/test02_companion1.s b/section_1/structs/test02_companion1.s new file mode 100644 index 0000000..d8d5759 --- /dev/null +++ b/section_1/structs/test02_companion1.s @@ -0,0 +1,21 @@ + .global main + .text + .align 2 + +main: + str x30, [sp, 16]! + + ldr x0, =fmt + ldr x1, =Bar + ldrh w2, [x1] + ldrb w3, [x1, 2] + ldr w4, [x1, 4] + bl printf + + ldr x30, [sp], 16 + mov w0, wzr + ret + + .data + +fmt: .asciz "%p a: 0x%x b: 0x%x c: 0x%x\n" diff --git a/section_1/structs/test02_companion2.s b/section_1/structs/test02_companion2.s new file mode 100644 index 0000000..767fa0c --- /dev/null +++ b/section_1/structs/test02_companion2.s @@ -0,0 +1,25 @@ + .global main + .text + .align 2 + + .equ foo_a, 0 # like #define + .equ foo_b, 2 # like #define + .equ foo_c, 4 # like #define + +main: + str x30, [sp, 16]! + + ldr x0, =fmt + ldr x1, =Bar + ldrh w2, [x1, foo_a] + ldrb w3, [x1, foo_b] + ldr w4, [x1, foo_c] + bl printf + + ldr x30, [sp], 16 + mov w0, wzr + ret + + .data + +fmt: .asciz "%p a: 0x%x b: 0x%x c: 0x%x\n" diff --git a/section_1/structs/test02_companion3.s b/section_1/structs/test02_companion3.s new file mode 100644 index 0000000..88108ad --- /dev/null +++ b/section_1/structs/test02_companion3.s @@ -0,0 +1,27 @@ + .global main + .text + .align 2 + +main: + str x30, [sp, 16]! + + ldr x0, =fmt + ldr x1, =Bar + ldrh w2, [x1, Foo.a] + ldrb w3, [x1, Foo.b] + ldr w4, [x1, Foo.c] + bl printf + + ldr x30, [sp], 16 + mov w0, wzr + ret + + .section Foo + .struct 0 // a starts at 0 and goes for 2 +Foo.a: .struct Foo.a + 2 // b starts at 2 and goes for 2 +Foo.b: .struct Foo.b + 2 // c starts at 4 +Foo.c: + + .data + +fmt: .asciz "%p a: 0x%x b: 0x%x c: 0x%x\n" diff --git a/section_1/structs/using.md b/section_1/structs/using.md new file mode 100644 index 0000000..d7e5306 --- /dev/null +++ b/section_1/structs/using.md @@ -0,0 +1,18 @@ +# Section 1 / Using Structs + +This topic has already been covered indirectly by examples provided in: + +* [alignment](./alignment.md) +* and [defining](./defining.md) + +To summarize using `structs`: + +* All `structs` have a base address + +* The base address corresponds to the beginning of the first data member + +* All subsequent data members are offsets relative to the first + +* In order to use a `struct` correctly, you must have first calculated the offsets of each data member + +* Sometimes there will be padding between data members due to the need to align all data members on natural boundaries.