前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >汇编学习(5),函数,栈帧

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

作者头像
一只小虾米
发布2022-12-07 15:53:46
4420
发布2022-12-07 15:53:46
举报
文章被收录于专栏:Android点滴分享Android点滴分享

本篇介绍

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

函数

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

代码语言:javascript
复制
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。

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

代码语言:javascript
复制
; 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。那体现到代码上是怎样呢?可以看下如下的代码:

代码语言:javascript
复制
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中再次执行一个进栈操作,就可以保证是对齐的了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-12-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本篇介绍
  • 函数
  • 栈帧
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档