美文网首页
汇编学习(5),函数,栈帧

汇编学习(5),函数,栈帧

作者: android小奉先 | 来源:发表于2022-12-04 18:48 被阅读0次

    本篇介绍

    本篇介绍下汇编中的函数,栈帧内容。

    函数

    汇编也支持函数调用,如下是一个例子:

    extern printf
    section .data                           
        radius  dq  10.0                
        pi      dq  3.14                
        fmt     db  "The area of the circle is %.2f, radius is %.2f",10,0
    section .bss                            
    section .text                                               
        global main                     
    ;----------------------------------------------
    main:
    push    rbp
    mov     rbp, rsp 
        call surface            ; call the function
        mov rdi,fmt             ; print format
        movsd xmm1, [radius]    ; move float to xmm1
        mov rax,2               ; surface in xmm0
        call printf
            leave
    ret
    ;----------------------------------------------
    surface:
    push    rbp
    mov     rbp, rsp        
        movsd xmm0, [radius]    ; move float to xmm0
        mulsd xmm0, [radius]    ; multiply xmm0 by float
        mulsd xmm0, [pi]        ; multiply xmm0 by float
    leave
    ret             
    
    输出:
    The area of the circle is 314.00, radius is 10.00
    

    使用call + 标号就可以实现函数调用,对于浮点,返回值会通过xmm0传递。

    这儿又出现了一个leave指令,leave就等同于 mov rsp,rbp,pop rbp。

    函数也可以拥有自己的代码段和数据段,如下面的例子:

    ; function2.asm
    extern printf
    section .data                           
        radius  dq  10.0                                
    section .bss                            
    section .text
    area:
        section .data
            .pi dq  3.141592654 ; local to area
        section .text 
    push rbp
    mov rbp, rsp
            movsd xmm0, [radius]
            mulsd xmm0, [radius]
            mulsd xmm0, [.pi]
    leave
    ret
    circum:
        section .data
            .pi dq  3.14        ; local to circum
        section .text
    push rbp
    mov rbp, rsp    
            movsd xmm0, [radius]
            addsd xmm0, [radius]
            mulsd xmm0, [.pi]
    leave
    ret
    circle:
        section .data
            .fmt_area   db  "The area is %f",10,0
            .fmt_circum db  "The circumference is %f",10,0
        section .text
    push rbp
    mov rbp, rsp        
            call area   
            mov rdi,.fmt_area
            mov rax,1           ; area in xmm0
            call printf
            call circum
            mov rdi,.fmt_circum
            mov rax,1           ; circumference in xmm0
            call printf
    leave
    ret
        global main                     
    main:
        mov rbp, rsp; for correct debugging
    push rbp
    mov rbp, rsp
        call circle
    leave
    ret
    
    输出:
    The area is 314.159265
    The circumference is 62.800000
    

    这儿可以看到在函数内部也可以定义数据段,用来存放局部变量。

    栈帧

    对于intel处理器,在调用函数的时候需要保证rsp是16字节对齐的,这样设计是为了更好的支持SIMD。那体现到代码上是怎样呢?可以看下如下的代码:

    extern printf
    section .data                           
        fmt db  "2 times pi equals %.14f",10,0 
        pi  dq  3.14159265358979
    section .bss                            
    section .text
    func3:
        push rbp
            movsd   xmm0, [pi]
            addsd   xmm0, [pi]
            mov     rdi,fmt
            mov     rax,1       
            call    printf  ; print a float
        pop rbp
        ret
    func2:
        push rbp
            call    func3   ; call the third function
        pop rbp
        ret
    func1:
        push rbp
            call    func2   ; call the second function
        pop rbp
        ret
    
        global main
    main:
        push rbp
            ;push rbp ; for align 16 byte, uncomment it will cause crash
            call func1  ; call the first function
            ;pop rbp
        pop rbp
        ret
    
    结果:
    2 times pi equals 6.28318530717958
    

    如果把main中注释的代码去掉,那么就会crash,因为这时候调用func1时 rsp就不是16字节对齐的。这儿可以单步看看:


    image.png

    这时候rsp没有16字节对齐,执行push rbp后,就会对齐。
    这就是prologue和epilogue的一个作用,保证调用函数时的rsp 16字节对齐。

    本来在调用main函数之前rsp是16字节对齐的,可是在调用main时候,由于会将返回地址压栈,这时候rsp就不是16字节对齐了,就需要prologue中再次执行一个进栈操作,就可以保证是对齐的了。

    相关文章

      网友评论

          本文标题:汇编学习(5),函数,栈帧

          本文链接:https://www.haomeiwen.com/subject/pdtmfdtx.html