繁体   English   中英

模块化编程 aarch64 汇编

[英]Modular programming aarch64 assembly

我有这个用于 arm 架构 64 的简单程序集,它将从我制作的宏中打印“Hello World\n”。

我们知道macro类似于高级编程中的function

所以我想要单独的宏到另一个文件。 这是我制作的汇编代码。

.data

.text
.globl _start

_start:

.macro print string
 b 2f // jump to label 2 forward (so it will not bother var)
 1: // label 1 (var declaration)
 .asciz "\string" // store argumen (string) in memory
 len_string = . - 1b // get len of string
 udf #0 // if i dont use this it will branch error :(
 2: // label 2 (main macro code)
 mov x0, #1 // file descriptor (1 means stdout)
 ldr x1, =1b // data to print (from label 1 back)
 ldr x2, =len_string //len of data
 mov x8, #0x40 // kernel convention 0x40 means writing
 svc #0 // SuperVisorCall kernel
.endm

print "Hello " // call macro
print "World\n" //call again

_exit: // exit code return 0
mov x0,#0
mov x8,#0x5d
svc #0

要验证它,请编译并运行该代码。 另存为hello.s并在 aarch64 设备(例如 android 或 raspi)中运行

as hello.s -o hello.o && ld hello.o -o hello && ./hello

所以从上面的代码中,我用参数string制作了名为print的宏。 但正如你所见,我在主程序中定义了宏。 我希望我可以将该print导入另一个源文件。 我应该怎么办?

高级函数的对应物是汇编函数。 汇编宏的对应物是高级语言中的宏或模板。

带函数的模块化编程

编写结构化或模块化代码的最简单方法是编写函数。 函数与您编写的非常相似,但您需要使用ret指令从它返回。 print函数获取您要在x0中打印的字符串的地址及其在x1中的长度。 它遵循AArch64 ABI并丢弃寄存器x0x1x2x8

        .text
        .type print, @function  // these two directives make the function
        .globl print            // callable from other object files.
print:  mov     x2, x1          // move length into place for syscall
        mov     x1, x0          // move string address into place for syscall
        mov     x0, #1          // print to stdout
        mov     x8, #0x40       // do a write system call
        svc     #0
        ret                     // return to caller

然后,您可以从您喜欢的任何目标文件中调用该函数:

        .data
hello:  .ascii "hello world\n"
len=    .-hello

        .text
        ldr     x0, =hello      // load string address from literal pool
        mov     x1, #len        // load string length
        bl      print           // call our print function

请注意,由于每个函数都使用相同的lr寄存器来跟踪返回地址,因此您可能需要将lr寄存器保存到调用其他函数的函数的堆栈中。 由于必须在 arm64 上成对将寄存器推入堆栈,因此我将xzr作为第二个寄存器推入。 在实践中,您可能想要推送一些需要保存的其他寄存器。

        str     lr, xzr, [sp, #-16]!  // push lr and xzr onto the stack
        ...
        ldr     x0, =hello            // load string address from literal pool
        mov     x1, #len              // load string length
        bl      print                 // call our print function
        ...
        ldr     lr, xzr, [sp], #16    // pop lr and xzr off the stack
        ret

使用宏进行模块化编程

您的宏观方法几乎是正确的。 这是一个稍微改进的版本。 请注意我们如何使用\@为使用的字符串生成唯一标签。 这允许我们不丢弃编号的标签,允许宏之外的代码使用它们。

        .macro  print string    // define a macro print with argument string
        .pushsection .data      // temporarily go into .data               
str\@:  .ascii  "\string"       // define the string
len\@=  .-str\@                 // and its length

        .popsection             // go back to the previous section
        mov     x0, #1          // print to stdout
        ldr     x1, =str\@      // print our string
        mov     x2, #len\@      // of this length
        mov     x8, #0x40       // with a write system call
        svc     #0              // do the system call!
        .endm

如果要调用其他文件中定义的宏,则必须将这些文件包含到其他文件中。 这可以通过.include指令来完成。 例如,假设您将宏放在名为macros.inc的文件中,您可以像这样包含它们:

        .include "macros.inc"       // include macros

有关详细信息,请参阅 GNU 手册

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM