• NASM汇编学习系列(2)——自定义函数和调用


    说明

    1. 本学习系列代码几乎完全摘自:asmtutor.com,如果英文可以的(也可以用谷歌浏览器翻译看),可以直接看asmtutor.com上的教程
    2. 本学习系列目录地址:https://www.cnblogs.com/whuwzp/p/nasm_contents.html
    3. 系统环境搭建:(我用的是ubuntu18.04.4 server,安装gcc、g++)
    sudo apt install nasm
    sudo apt install gcc-multilib
    

    0. 概览

    1. 承前:上一节,我们调用sys_write时第三个参数字符串长度是固定长度13,那么如果改变了字符串,我们就得改,很不方便,能不能自动计算长度呢?
    2. 启后:本节,自动计算字符串长度,并且改写成函数形式,调用自定义的strlen函数

    1. 计算字符串长度

    算法思路是:

    1. ebx和eax先同时赋值为msg的地址;
    2. eax递增(地址+1),比较[eax]=='',如果不是0就继续递增eax,否则退出
    3. 计算eax-ebx,这样就是字符串的长度了,差值保存在eax中

    以下代码摘自:https://asmtutor.com/#lesson3

    ; Hello World Program (Calculating string length)
    ; 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 ; we can modify this now without having to update anywhere else in the program
     
    SECTION .text
    global  _start
     
    _start:
     
        mov     ebx, msg        ; move the address of our message string into EBX
        mov     eax, ebx        ; move the address in EBX into EAX as well (Both now point to the same segment in memory)
     
    nextchar:
        cmp     byte [eax], 0   ; compare the byte pointed to by EAX at this address against zero (Zero is an end of string delimiter)
        jz      finished        ; jump (if the zero flagged has been set) to the point in the code labeled 'finished'
        inc     eax             ; increment the address in EAX by one byte (if the zero flagged has NOT been set)
        jmp     nextchar        ; jump to the point in the code labeled 'nextchar'
     
    finished:
        sub     eax, ebx        ; subtract the address in EBX from the address in EAX
                                ; remember both registers started pointing to the same address (see line 15)
                                ; but EAX has been incremented one byte for each character in the message string
                                ; when you subtract one memory address from another of the same type
                                ; the result is number of segments between them - in this case the number of bytes
     
        mov     edx, eax        ; EAX now equals the number of bytes in our string
        mov     ecx, msg        ; the rest of the code should be familiar now
        mov     ebx, 1
        mov     eax, 4
        int     80h
     
        mov     ebx, 0
        mov     eax, 1
        int     80h
    

    编译、链接和运行方法:(其实代码中已经写了)

    nasm -f elf helloworld-len.asm
    ld -m elf_i386 helloworld-len.o -o helloworld-len
    # Run with: 
    ./helloworld-len
    

    2. 将计算长度的功能写为函数

    如果以后也要用到计算字符串长度就很麻烦,所以写成函数,提升代码重用率。

    以下摘自:https://asmtutor.com/#lesson4

    ; 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
    

    这一段意思很简单,不多说:

    1. 函数调用参数依次保存在eax, ebx, ecx, edx中
    2. 函数的返回值存放于eax,call strlen之后的mov edx, eax,就是把计算结果(字符串长度eax赋值到edx中,这个edx是sys_write的第三个参数)
    3. 注意:strlen中的push ebxpop ebx从功能上是没啥意义的,但是,后面的示例中将会大量使用push eax, pop eax, push ebx, pop ebx等,这样做是为了保存寄存器中的内容,因为strlen中mov ebx, eax把ebx中的内容修改了,当我们退出strlen函数后,ebx的值就不是原先的值了,这样可能会对调用strlen的函数造成影响。所以push ebx保存到栈上,然后退出函数前pop ebx还原,这样函数返回后,寄存器的状态还是和以前一样,没有影响(eax作为保存返回值的寄存器,内容会改变)
  • 相关阅读:
    tkinter 改变按钮状态
    python 遗传算法精简版
    极简反传(BP)神经网络
    python 操作注册表
    python 调用 shell 命令方法
    Python标准库:内置函数dict(mapping, **kwarg)
    3.2.2 正則表達式的功能
    NSArray利用Cocoa框架进行汉字排序
    Java多线程具体解释
    android6.0权限管理工具EasyPermissionUtil
  • 原文地址:https://www.cnblogs.com/whuwzp/p/nasm_strlen.html
Copyright © 2020-2023  润新知