mirror of
https://github.com/pkivolowitz/asm_book.git
synced 2026-06-21 00:26:46 +08:00
detailed example of using argv
This commit is contained in:
parent
6ba7a1c60d
commit
84938166f3
3 changed files with 268 additions and 0 deletions
|
|
@ -324,6 +324,7 @@ contained therein are applicable to all languages.
|
|||
| 6 | [Calling Assembly Language From Python](./python/) | [Link](./python/README.pdf) |
|
||||
| 7 | [Atomic Operations](./more/atomics/README.md) | [Link](./more/atomics/README.pdf) |
|
||||
| 8 | [Jump Tables](./more/jump_tables/README.md) | [Link](./more/jump_tables/README.pdf) |
|
||||
| 9 | [argv](./more/argv_example/jess1.S) | ASM CODE |
|
||||
| - | [Debugging Lecture](./debugging/Discourses%20and%20Dialogs%20on%20Debugging.pptx) | PPTX |
|
||||
|
||||
## Macro Suite
|
||||
|
|
|
|||
156
more/argv_example/apple-linux-convergence.S
Normal file
156
more/argv_example/apple-linux-convergence.S
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/* Macros to permit the "same" assembly language to build on ARM64
|
||||
Linux systems as well as Apple Silicon systems.
|
||||
|
||||
See the fuller documentation at:
|
||||
https://github.com/pkivolowitz/asm_book/blob/main/macros/README.md
|
||||
|
||||
Perry Kivolowitz
|
||||
A Gentle Introduction to Assembly Language
|
||||
*/
|
||||
|
||||
.macro GLD_PTR xreg, label
|
||||
#if defined(__APPLE__)
|
||||
adrp \xreg, _\label@GOTPAGE
|
||||
ldr \xreg, [\xreg, _\label@GOTPAGEOFF]
|
||||
#else
|
||||
ldr \xreg, =\label
|
||||
ldr \xreg, [\xreg]
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro GLD_ADDR xreg, label // Get a global address
|
||||
#if defined(__APPLE__)
|
||||
adrp \xreg, _\label@GOTPAGE
|
||||
add \xreg, \xreg, _\label@GOTPAGEOFF
|
||||
#else
|
||||
ldr \xreg, =\label
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro LLD_ADDR xreg, label
|
||||
#if defined(__APPLE__)
|
||||
adrp \xreg, \label@PAGE
|
||||
add \xreg, \xreg, \label@PAGEOFF
|
||||
#else
|
||||
ldr \xreg, =\label
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro LLD_DBL xreg, dreg, label
|
||||
#if defined(__APPLE__)
|
||||
adrp \xreg, \label@PAGE
|
||||
add \xreg, \xreg, \label@PAGEOFF
|
||||
ldur \dreg, [\xreg]
|
||||
// fmov \dreg, \xreg
|
||||
#else
|
||||
ldr \xreg, =\label
|
||||
ldur \dreg, [\xreg]
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro LLD_FLT xreg, sreg, label
|
||||
#if defined(__APPLE__)
|
||||
adrp \xreg, \label@PAGE
|
||||
add \xreg, \xreg, \label@PAGEOFF
|
||||
ldur \sreg, [\xreg]
|
||||
#else
|
||||
ldr \xreg, =\label
|
||||
ldur \sreg, [\xreg]
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro GLABEL label
|
||||
#if defined(__APPLE__)
|
||||
.global _\label
|
||||
#else
|
||||
.global \label
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro MAIN
|
||||
#if defined(__APPLE__)
|
||||
_main:
|
||||
#else
|
||||
main:
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/* Fetching the address of the externally defined errno is quite
|
||||
different on Apple and Linux. This macro leaves the address of
|
||||
errno in x0.
|
||||
*/
|
||||
.macro ERRNO_ADDR
|
||||
#if defined(__APPLE__)
|
||||
bl ___error
|
||||
#else
|
||||
bl __errno_location
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro CRT label
|
||||
#if defined(__APPLE__)
|
||||
bl _\label
|
||||
#else
|
||||
bl \label
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro START_PROC // after starting label
|
||||
.cfi_startproc
|
||||
.endm
|
||||
|
||||
.macro END_PROC // after the return
|
||||
.cfi_endproc
|
||||
.endm
|
||||
|
||||
.macro PUSH_P a, b
|
||||
stp \a, \b, [sp, -16]!
|
||||
.endm
|
||||
|
||||
.macro PUSH_R a
|
||||
str \a, [sp, -16]!
|
||||
.endm
|
||||
|
||||
.macro POP_P a, b
|
||||
ldp \a, \b, [sp], 16
|
||||
.endm
|
||||
|
||||
.macro POP_R a
|
||||
ldr \a, [sp], 16
|
||||
.endm
|
||||
|
||||
/* The smaller of src_a and src_b is put into dest. A cmp instruction
|
||||
or other instruction that sets the flags must be performed first.
|
||||
This macro makes it easy to remember which register does what in the
|
||||
csel.
|
||||
|
||||
Thank you to u/TNorthover for nudge to add the cmp.
|
||||
*/
|
||||
|
||||
.macro MIN src_a, src_b, dest
|
||||
cmp \src_a, \src_b
|
||||
csel \dest, \src_a, \src_b, LT
|
||||
.endm
|
||||
|
||||
/* The larger of src_a and src_b is put into dest. A cmp instruction
|
||||
or other instruction that sets the flags must be performed first.
|
||||
This macro makes it easy to remember which register does what in the
|
||||
csel.
|
||||
|
||||
Thank you to u/TNorthover for nudge to add the cmp.
|
||||
*/
|
||||
|
||||
.macro MAX src_a, src_b, dest
|
||||
cmp \src_a, \src_b
|
||||
csel \dest, \src_a, \src_b, GT
|
||||
.endm
|
||||
|
||||
.macro AASCIZ label, string
|
||||
.p2align 2
|
||||
\label: .asciz "\string"
|
||||
.endm
|
||||
|
||||
.macro MOD src_a, src_b, dest, scratch
|
||||
sdiv \scratch, \src_a, \src_b
|
||||
msub \dest, \scratch, \src_b, \src_a
|
||||
.endm
|
||||
111
more/argv_example/jess1.S
Normal file
111
more/argv_example/jess1.S
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
#include "apple-linux-convergence.S"
|
||||
|
||||
.p2align 2
|
||||
.text
|
||||
GLABEL main
|
||||
|
||||
/* This program will get a string followed by a double followed by an
|
||||
integer from the command line demonstrating how each of these types
|
||||
can be retrieved.
|
||||
|
||||
Example:
|
||||
./a.out test 29.3 29
|
||||
*/
|
||||
|
||||
MAIN
|
||||
PUSH_P x29, x30
|
||||
mov x29, sp
|
||||
|
||||
// Check argc to see if it is 4. This is not the only way to
|
||||
// validate command line arguments but it is an easy way.
|
||||
cmp w0, 4
|
||||
bne 99f // take branch if argc isn't "right".
|
||||
|
||||
// Skip past argv[0]
|
||||
add x1, x1, 8
|
||||
|
||||
// Fetch argv[1] as a string.
|
||||
// x1 is a pointer to a pointer to chars (i.e. the string).
|
||||
// Being a pointer to a pointer, it must be dereferenced to
|
||||
// make a pointer.
|
||||
ldr x0, [x1] // dereference
|
||||
// Now x0 contains a pointer to the command line argument.
|
||||
// Print the string (as a string). But doing this causes a
|
||||
// function call which will destroy x1. So, save x1 temporarily.
|
||||
// This could be avoided if x1 were moved to a backed up x
|
||||
// register (e.g. x20).
|
||||
PUSH_R x1
|
||||
CRT puts // ptr is in x0 where puts() needs it.
|
||||
POP_R x1
|
||||
|
||||
// Advance x1 once again to get to argv[2] which can be done
|
||||
// in the same instruction as dereferencing it use a
|
||||
// preincrement.
|
||||
ldr x0, [x1, 8]! // dereference
|
||||
|
||||
// Now the string version of argv[2] is now pointed to by x0.
|
||||
// This is exactly where atof would want it. We need atof
|
||||
// because it turns strings into numbers. BUT, same as before,
|
||||
// calling a function would destroy x1 so let's do the same
|
||||
// trick of backing up x1 on the stack and then restoring after
|
||||
// the function call.
|
||||
PUSH_R x1
|
||||
CRT atof // ptr is in x0 where atof() needs it.
|
||||
POP_R x1
|
||||
// The string value will be converted to a double left in d0.
|
||||
// d0 is also a scratch register so for our next call to atoi,
|
||||
// d0 will have to be preserved on the stack - alternatively,
|
||||
// we could have used a high d register backed up and restored
|
||||
// at the start and ending of main().
|
||||
|
||||
// Advance x1 once again to get to argv[3] which can be done
|
||||
// in the same instruction as dereferencing it use a
|
||||
// preincrement.
|
||||
ldr x0, [x1, 8]! // dereference
|
||||
|
||||
// Now the string version of argv[3] is now pointed to by x0.
|
||||
// This is exactly where atoi would want it. We need atoi
|
||||
// because it turns strings into numbers. BUT, same as before,
|
||||
// calling a function would destroy x1 so let's do the same
|
||||
// trick of backing up x1 on the stack and then restoring after
|
||||
// the function call. We must also do the same for d0. Actually,
|
||||
// we won't need argv after this so we will skip backing up x1.
|
||||
|
||||
PUSH_R d0
|
||||
CRT atoi // ptr is in x0 where atof() needs it.
|
||||
POP_R d0
|
||||
// d0 now contains the double.
|
||||
// x0 now contains the integer.
|
||||
// x0 must be copied to x1 because x0 must be a pointer to fmt
|
||||
// for printf to work.
|
||||
mov x1, x0
|
||||
LLD_ADDR x0, fmt
|
||||
#if defined(__APPLE__)
|
||||
sub sp, sp, 16
|
||||
str x1, [sp, 8]
|
||||
str d0, [sp]
|
||||
CRT printf
|
||||
add sp, sp, 16
|
||||
#else
|
||||
bl printf
|
||||
#endif
|
||||
|
||||
99: POP_P x29, x30
|
||||
mov w0, wzr
|
||||
ret
|
||||
|
||||
/* What did we learn?
|
||||
* x1 has argv when main begins.
|
||||
* pointers to the arguments are the contents of argv NOT
|
||||
the actual values. Therefore, x1, which is a pointer (to a pointer),
|
||||
must be dereferenced to get to the actual pointer. In the code,
|
||||
there are three lines with the comment "// dereference".
|
||||
* all command line arguments are c-strings. If that's not what you
|
||||
want, they must be converted - see the code for atoi and atof for
|
||||
examples.
|
||||
*/
|
||||
.data
|
||||
|
||||
fmt: .asciz "double: %f integer: %d\n"
|
||||
|
||||
.end
|
||||
Loading…
Reference in a new issue