WTF was I thinking before?

This commit is contained in:
Perry Kivolowitz 2024-02-28 10:47:55 -06:00
parent c020675cd7
commit 697a9c0e87
6 changed files with 190 additions and 160 deletions

View file

@ -4,9 +4,9 @@ Given:
```c
struct Foo {
short a;
char b;
int c;
short a;
char b;
int c;
};
struct Foo Bar = { 0xaaaa, 0xbb, 0xcccccccc };
@ -15,62 +15,68 @@ 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
#include "apple-linux-convergence.S" // 1
// 2
GLABEL main // 3
.text // 4
.p2align 2 // 5
// 6
MAIN // 7
PUSH_P x29, x30 // 8
mov x29, sp // 9
// 10
LLD_ADDR x0, fmt // 11
LLD_ADDR x1, bar // 12
ldrh w2, [x1, 0] // 13
ldrb w3, [x1, 2] // 14
ldr w4, [x1, 4] // 15
#if defined(__APPLE__) // 16
PUSH_P x3, x4 // 17
PUSH_P x1, x2 // 18
CRT printf // 19
add sp, sp, 32 // 20
#else // 21
CRT printf // 22
#endif // 23
POP_P x29, x30 // 24
mov w0, wzr // 25
ret // 26
// 27
.data // 28
// 29
fmt: .asciz "%p a: 0x%lx b: %x c: %x\n" // 30
bar: .short 0xaaaa // 31
.byte 0xbb // 32
.byte 0 // padding // 33
.word 0xcccccccc // 34
// 35
.end // 36
```
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`.
It would be understandable if you don't see where the structure of the
`struct` is being specified in the code. That's because it isn't.
Rather, focus on the 0, 2 and 4 on lines 30 through 32. These are the
hard coded offsets of the struct's fields `a`, `b` and `c`.
[Here](./test02_companion2.s) is a second way to define a `struct`.
A second way to define the offsets of the fields within a struct which
is preferable to the one above is excerpted here.
The full text of the file is located
[here](./test02_companion2.s).
```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
.equ foo_a, 0 // like #define
.equ foo_b, 2 // like #define
.equ foo_c, 4 // like #define
```
and here:
```text
ldrh w2, [x1, foo_a]
ldrb w3, [x1, foo_b]
ldr w4, [x1, foo_c]
```
This method uses `.equ` to make the offsets into symbolic constants.
@ -78,45 +84,28 @@ 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
#define foo_a 0
#define foo_b 2
#define foo_c 4
```
Finally, [here](./test02_companion3.s) is a third way of defining `structs`.
Finally, [here](./test02_companion3.s) is a third way of defining
`structs`. However, this method works on Linux but not on Apple. We have
not yet discovered the incantation that allows something like this on
Apple.
The salient Linux-only code is excerpted below:
```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
.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:
```
This method has a *substantial* benefit over the previous methods. Imagine
you need to insert a new field between `Foo.a` and `Foo.b`. Simply do so.
If you're using this third method, which is based on relative offsets, the
assembler will do the work of adjusting the following offsets for you.
This method has a *substantial* benefit over the previous methods.
Imagine you need to insert a new field between `Foo.a` and `Foo.b`.
Simply do so. If you're using this third method, which is based on
relative offsets, the assembler will do the work of adjusting the
following offsets for you.

View file

@ -1,21 +0,0 @@
.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"

View file

@ -0,0 +1,15 @@
.arch armv8-a
.file "test02.c"
.text
.global Bar
.data
.align 3
.type Bar, %object
.size Bar, 8
Bar:
.hword -21846
.byte -69
.zero 1
.word -858993460
.ident "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
.section .note.GNU-stack,"",@progbits

View file

@ -1,21 +1,36 @@
.global main
.text
.align 2
#include "apple-linux-convergence.S"
main:
str x30, [sp, 16]!
GLABEL main
.text
.p2align 2
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
MAIN
PUSH_P x29, x30
mov x29, sp
.data
LLD_ADDR x0, fmt
LLD_ADDR x1, bar
ldrh w2, [x1, 0]
ldrb w3, [x1, 2]
ldr w4, [x1, 4]
#if defined(__APPLE__)
PUSH_P x3, x4
PUSH_P x1, x2
CRT printf
add sp, sp, 32
#else
CRT printf
#endif
POP_P x29, x30
mov w0, wzr
ret
fmt: .asciz "%p a: 0x%x b: 0x%x c: 0x%x\n"
.data
fmt: .asciz "%p a: 0x%lx b: %x c: %x\n"
bar: .short 0xaaaa
.byte 0xbb
.byte 0 // padding
.word 0xcccccccc
.end

View file

@ -1,25 +1,40 @@
.global main
#include "apple-linux-convergence.S"
GLABEL main
.text
.align 2
.p2align 2
.equ foo_a, 0 # like #define
.equ foo_b, 2 # like #define
.equ foo_c, 4 # like #define
.equ foo_a, 0 // like #define
.equ foo_b, 2 // like #define
.equ foo_c, 4 // like #define
main:
str x30, [sp, 16]!
MAIN
PUSH_P x29, x30
mov x29, sp
ldr x0, =fmt
ldr x1, =Bar
LLD_ADDR x0, fmt
LLD_ADDR x1, bar
ldrh w2, [x1, foo_a]
ldrb w3, [x1, foo_b]
ldr w4, [x1, foo_c]
bl printf
ldr x30, [sp], 16
ldrb w3, [x1, foo_b]
ldr w4, [x1, foo_c]
#if defined(__APPLE__)
PUSH_P x3, x4
PUSH_P x1, x2
CRT printf
add sp, sp, 32
#else
CRT printf
#endif
POP_P x29, x30
mov w0, wzr
ret
.data
fmt: .asciz "%p a: 0x%x b: 0x%x c: 0x%x\n"
fmt: .asciz "%p a: 0x%lx b: %x c: %x\n"
bar: .short 0xaaaa
.byte 0xbb
.byte 0 // padding
.word 0xcccccccc
.end

View file

@ -1,27 +1,44 @@
.global main
#include "apple-linux-convergence.S"
// STRUCT DEFINITION WORKS ONLY FOR LINUX
GLABEL main
.text
.align 2
.p2align 2
main:
str x30, [sp, 16]!
MAIN
PUSH_P x29, x30
mov x29, sp
ldr x0, =fmt
ldr x1, =Bar
LLD_ADDR x0, fmt
LLD_ADDR x1, bar
ldrh w2, [x1, Foo.a]
ldrb w3, [x1, Foo.b]
ldr w4, [x1, Foo.c]
bl printf
ldr x30, [sp], 16
ldrb w3, [x1, Foo.b]
ldr w4, [x1, Foo.c]
#if defined(__APPLE__)
PUSH_P x3, x4
PUSH_P x1, x2
CRT printf
add sp, sp, 32
#else
CRT printf
#endif
POP_P x29, x30
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:
.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"
fmt: .asciz "%p a: 0x%lx b: %x c: %x\n"
bar: .short 0xaaaa
.byte 0xbb
.byte 0 // padding
.word 0xcccccccc
.end