首页 > 寺庙

NASM汇编语言基础_子程序subroutines|

NASM汇编语言基础_子程序subroutines

0x00 简介

NASM汇编语言基础_子程序subroutines|

子程序(又称 子例程)相当于函数。它们是可重用的代码段,程序可以调用它们来执行各种可重复的任务。子例程使用标签声明,就像我们以前使用过的标签一样( 例如,_start:)但是,我们不使用 JMP 指令来调用它们 —— 而是使用新的指令 CALL。在运行函数后,我们也不会使用 JMP 指令返回到我们的程序。为了从子程序返回到我们的程序,我们改用指令 RET。

0x01 原理

_那么我们为什么不使用 JMP 指令调用子程序:

编写子程序的一大好处是我们可以重复调用它。如果我们想要能够在代码中的任何位置使用子程序,我们必须编写一些逻辑来确定我们在代码中跳转到的位置 以及 应该跳回的位置。这将使我们的代码与不需要的标签混杂在一起。但是,如果我们使用 CALL 和 RET,程序集会使用称为堆栈的数据结构来处理此问题。

_什么是堆栈:

堆栈是一种特殊的数据结构。这与我们以前所使用过的内存类型相同,但它在程序如何使用内存方面很特别:堆栈是所谓的 后进先出(LIFO) 结构。一个形象的例子是我们把书籍叠在桌子上,最后放上去的那本书总是位于顶层,所以我们拿书的时候也从最后放上去的那本开始。

尽管程序集中的堆栈不存储在纸质书本中,堆栈用于存储值。你可以在堆栈上存储许多内容,例如变量、地址或其他程序。当我们调用函数(子程序)来临时存储稍后将被复原的值时,我们就需要运用到堆栈。

函数需要使用到的任何寄存器都应该将其当前的值存放到堆栈上,我们使用 PUSH 指令对其进行安全保存。然后,在函数完成执行之后,可以使用 POP 指令还原这些寄存器的原始值。这意味着寄存器中的任何值在调用函数之前与之后都是相同的。如果我们在子程序中处理这一点,我们可以调用函数,而不必担心它们对我们的寄存器进行了哪些更改。

CALL 和 RET 指令也使用堆栈。调用函数时,从调用它时 的地址将被 PUSH 到堆栈上。然后,RET 会弹出此地址,程序将跳回代码中的位置。这就是为什么你应该总是 JMP 到标签,但应该调用函数。

0x02 实现

;hello.asm

;子例程版本

;使用 nasm -f elf hello.asm 汇编

;使用 ld -m elf_i386 hello.o -o hello 链接

;使用 ./hello 运行

SECTION .data

msg db hello, ASSWECAN !!!, 0ah, 0dh, 0

SECTION .text

global _start

_start:

mov eax, msg ;把 msg 的初始地址存入eax寄存器

call strlen ;调用函数 strlen 来计算字符串长度

mov edx, eax ;strlen 函数将结果存放在了eax寄存器中

mov ecx, msg ;接下来的与上个程序相似

mov ebx, 1

mov eax, 4

int 80h

mov ebx, 0

mov eax, 1

int 80h

strlen:;这是我们编写的第一个函数声明

push ebx;我们将ebx的数据保存到堆栈中,这样它就不会被函数改变

mov ebx, eax;与上一个程序相似

nextchar:

cmp byte [eax], 0

jz finished

inc eax

jmp nextchar

finished:

sub eax, ebx

pop ebx;将堆栈中保存的ebx值返回到ebx寄存器中

ret;返回调用函数的地方


|NASM汇编语言基础_子程序subroutines

   

NASM汇编语言基础_子程序subroutines|
  • 如何,堆栈,ps|
  • 如何,堆栈,ps| | 如何,堆栈,ps| ...

    NASM汇编语言基础_子程序subroutines|
  • 如何学习汇编语言|
  • 如何学习汇编语言| | 如何学习汇编语言| ...

    NASM汇编语言基础_子程序subroutines|
  • null啥意思c语言|
  • null啥意思c语言| | null啥意思c语言| ...