JSRUN 用代码说话

子程序功能

编辑教程

子程序功能

它们是可重用的代码段,您的程序可以调用它们来执行各种可重复的任务。子例程使用标签声明,就像我们以前使用的(例如。_start:)然而,我们不使用JMP指令到达它们-相反,我们使用一个新的指令CALL。在运行函数之后,我们也不使用JMP指令返回程序。要从子例程返回到我们的程序,我们使用指令RET代替。

为什么我们不使用JMP来实现子程序呢?

编写子程序的好处是我们可以重用它。如果我们想要在代码的任何地方使用子例程,我们就必须编写一些逻辑来确定我们从代码的哪个位置跳转以及应该跳转到哪个位置。这将使我们的代码充满不必要的标签。然而,如果我们使用CALL和RET,程序集就会使用称为堆栈的东西来处理这个问题。

堆栈简介

堆栈是一种特殊类型的内存。这是我们之前使用过的相同类型的内存,但是它在我们的程序中是特殊的。栈就是所谓的后进先出内存(LIFO)。你可以把它想象成厨房里的一堆盘子。你放的最后一个盘子也是你下次用盘子的时候拿下来的第一个盘子。

堆栈在汇编中不存储板,但它的存储值。您可以在堆栈上存储很多东西,比如变量、地址或其他程序。当调用子例程临时存储稍后将恢复的值时,我们需要使用堆栈。

你的函数需要使用的任何寄存器都应该使用PUSH指令将其当前值放在堆栈上以安全保存。然后,在函数完成其逻辑之后,这些寄存器可以使用POP指令恢复其原始值。这意味着寄存器中的任何值在调用函数之前和之后都是相同的。如果我们在子例程中处理这一点,我们就可以调用函数,而不用担心它们对寄存器做了什么改变。

CALL和RET指令也使用堆栈。当你调用一个子程序时,你在程序中调用它的地址被压入堆栈。然后RET将该地址从堆栈中弹出,程序将跳回代码中的那个位置。这就是为什么你应该总是JMP标签,但你应该调用函数。

; Hello World Program (Subroutines)
; Compile with: nasm -f elf helloworld-len.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 helloworld-len.o -o helloworld-len
; Run with: ./helloworld-len

SECTION .data
msg     db      'Hello, brave new world!', 0Ah

SECTION .text
global  _start

_start:

    mov     eax, msg        ; move the address of our message string into EAX
    call    strlen          ; call our function to calculate the length of the string

    mov     edx, eax        ; our function leaves the result in EAX
    mov     ecx, msg        ; this is all the same as before
    mov     ebx, 1
    mov     eax, 4
    int     80h

    mov     ebx, 0
    mov     eax, 1
    int     80h

strlen:                     ; this is our first function declaration
    push    ebx             ; push the value in EBX onto the stack to preserve it while we use EBX in this function
    mov     ebx, eax        ; move the address in EAX into EBX (Both point to the same segment in memory)

nextchar:                   ; this is the same as lesson3
    cmp     byte [eax], 0
    jz      finished
    inc     eax
    jmp     nextchar

finished:
    sub     eax, ebx
    pop     ebx             ; pop the value on the stack back into EBX
    ret                     ; return to where the function was called
~$ nasm -f elf helloworld-len.asm
~$ ld -m elf_i386 helloworld-len.o -o helloworld-len
~$ ./helloworld-len
Hello, brave new world!
JSRUN闪电教程系统是国内最先开创的教程维护系统, 所有工程师都可以参与共同维护的闪电教程,让知识的积累变得统一完整、自成体系。 大家可以一起参与进共编,让零散的知识点帮助更多的人。
X
支付宝
9.99
无法付款,请点击这里
金额: 0
备注:
转账时请填写正确的金额和备注信息,到账由人工处理,可能需要较长时间
如有疑问请联系QQ:565830900
正在生成二维码, 此过程可能需要15秒钟