mirror of
https://github.com/pkivolowitz/asm_book.git
synced 2026-06-23 23:46:48 +08:00
more bigger faster
This commit is contained in:
parent
918ce23f57
commit
29b1367730
13 changed files with 339 additions and 345 deletions
15
README.md
15
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.
|
hope to add a chapter detailing the Windows calling convention.
|
||||||
|
|
||||||
You'll notice right away that we make use of the C-runtime directly
|
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
|
rather than make OS service calls. So, for instance, if we want to call
|
||||||
call `write()`, we call `write` from the assembly language. This
|
`write()`, we call `write` from the assembly language. This version of
|
||||||
version of the system call `write` is a wrapper function built into
|
the system call `write` is a wrapper function built into the C-runtime
|
||||||
the C-runtime which handles the low level details of performing a
|
which handles the low level details of performing a system call. See the
|
||||||
system call. See the [chapter](./not_written_yet.md) on what actually
|
[here](./more/system_calls/README.md) on what actually happens inside
|
||||||
happens inside these wrapper functions.
|
these wrapper functions.
|
||||||
|
|
||||||
## A Lot of Names
|
## A Lot of Names
|
||||||
|
|
||||||
|
|
@ -217,7 +217,7 @@ knowledge - how cool is that!
|
||||||
| 6 | Functions | |
|
| 6 | Functions | |
|
||||||
| .... a | [.... Calling and Returning](./section_1/funcs/README.md) | NA |
|
| .... a | [.... Calling and Returning](./section_1/funcs/README.md) | NA |
|
||||||
| .... b | [.... Passing Parameters](./section_1/funcs/README2.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 |
|
| 7 | [FizzBuzz - a Complete Program](./section_1/fizzbuzz/README.md) | NA |
|
||||||
| 8 | Structs | |
|
| 8 | Structs | |
|
||||||
| .... a | [.... Alignment](./section_1/structs/alignment.md) | NA |
|
| .... 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 |
|
| Chapter | Markdown | PDF |
|
||||||
| ------- | -------- | --- |
|
| ------- | -------- | --- |
|
||||||
| --- | [Determining string literal lengths for C functions](./more/strlen_for_c/README.md) | NA |
|
| --- | [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
|
## Projects
|
||||||
|
|
||||||
|
|
|
||||||
178
more/system_calls/README.md
Normal file
178
more/system_calls/README.md
Normal file
|
|
@ -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 <iostream> // 1
|
||||||
|
#include <unistd.h> // 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 <stdio.h> // 1
|
||||||
|
#include <unistd.h> // 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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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.
|
||||||
BIN
more/system_calls/getpid/getpid.png
Normal file
BIN
more/system_calls/getpid/getpid.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 372 KiB |
7
more/system_calls/getpid/main.c
Normal file
7
more/system_calls/getpid/main.c
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
printf("Greetings from: %d\n", getpid());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
10
more/system_calls/getpid/main.cpp
Normal file
10
more/system_calls/getpid/main.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
using std::cout;
|
||||||
|
using std::endl;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cout << "Greetings from: " << getpid() << endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
17
more/system_calls/getpid/main_asm.s
Normal file
17
more/system_calls/getpid/main_asm.s
Normal file
|
|
@ -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
|
||||||
18
more/system_calls/getpid/main_direct.s
Normal file
18
more/system_calls/getpid/main_direct.s
Normal file
|
|
@ -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
|
||||||
|
|
@ -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
|
This chapter gives an example of calling the most common C I/O functions
|
||||||
assembly language.
|
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
|
## Low level file operations
|
||||||
|
|
||||||
The following example shows `open()`, `close()`, `read()`, `write()`
|
This example [program](./file_ops.s) makes use of `open()`, `close()`,
|
||||||
and `lseek()`.
|
`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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
6
section_1/funcs/seek.c
Normal file
6
section_1/funcs/seek.c
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void Foo() {
|
||||||
|
write(0, 0, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
21
section_1/funcs/seek.s
Normal file
21
section_1/funcs/seek.s
Normal file
|
|
@ -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
|
||||||
1
section_1/funcs/test.txt
Normal file
1
section_1/funcs/test.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
some data
|
||||||
|
|
@ -13,27 +13,24 @@ The TL;DR of endianness is this:
|
||||||
|
|
||||||
* suppose you have a pointer to a `short`
|
* 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?
|
of the `short` or the second?
|
||||||
|
|
||||||
* this extends to `int` and to `long` as well
|
This extends to `int` and to `long` as well.
|
||||||
|
|
||||||
That's the essential nugget.
|
|
||||||
|
|
||||||
## Why talk about this?
|
## Why talk about this?
|
||||||
|
|
||||||
Endianness is mostly hidden from you. The value of an `int` is the value
|
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.
|
radar.
|
||||||
|
|
||||||
Endianness is a big deal for people who code network applications where
|
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
|
the first one transmitted over the wire. Network Byte Order is big
|
||||||
endian. Unfortunately, most of todays very popular processors are
|
endian. Most of todays very popular processors are little endian.
|
||||||
little endian.
|
|
||||||
|
|
||||||
For us assembly language coders, endianness comes into play when we're
|
For us assembly language coders, endianness especially comes into play
|
||||||
using our debuggers. After all, when we examine memory, memory is a
|
when we're using our debuggers. When we examine memory, memory is a
|
||||||
linear stream of bytes. Without understanding endianness, you might be
|
linear stream of bytes. Without understanding endianness, you might be
|
||||||
confused about what you're seeing.
|
confused about what you're seeing.
|
||||||
|
|
||||||
|
|
@ -48,8 +45,10 @@ end.
|
||||||
|
|
||||||
Please read the entirety of Gulliver's Travels keeping in mind how
|
Please read the entirety of Gulliver's Travels keeping in mind how
|
||||||
absolutely nasty Swift's portrayal of 18th century politics can be. You
|
absolutely nasty Swift's portrayal of 18th century politics can be. You
|
||||||
won't be disappointed. And no, the classic cartoon version, Max
|
won't be disappointed.
|
||||||
Fleischer's 1939 masterpiece, doesn't do the book justice.
|
|
||||||
|
The classic cartoon version, Max Fleischer's 1939 masterpiece, doesn't
|
||||||
|
do the book justice.
|
||||||
|
|
||||||
## How do the terms apply?
|
## 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
|
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
|
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.**
|
**Notice I have not discussed strings.**
|
||||||
|
|
||||||
|
|
@ -122,17 +121,17 @@ string Dump(T & i) { // 15
|
||||||
} // 24
|
} // 24
|
||||||
```
|
```
|
||||||
|
|
||||||
First, you might not be familiar with templated functions. Notice
|
You might not be familiar with templated functions. Notice line 14 tells
|
||||||
line 14 tells the compiler that the next function is templated and that
|
the compiler that the next function is templated and that `T` will stand
|
||||||
`T` be take on the value matching the parameter that is actually given
|
in for the type matching the parameter that is actually given to the
|
||||||
to the function.
|
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()`
|
of `int`, `short` and `long`. When the compiler gets to the `sizeof()`
|
||||||
on line 20, the size of the "right" type is taken.
|
on line 20, the size of the "right" type is taken.
|
||||||
|
|
||||||
Using the templated approach we need write this function only once
|
Using the templated approach, we need write this function only once
|
||||||
rather than three times for each of `int`, `short` and `long`.
|
rather than three times (for each of `int`, `short` and `long`).
|
||||||
|
|
||||||
## Output on a little endian machine
|
## 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.
|
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
|
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
|
`long`. We then tried specifying the `long` as a `long long`. Apparently
|
||||||
there is little support for 64 bit numbers on this ancient but
|
there is little support for 64 bit numbers on this ancient but
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue