zoukankan      html  css  js  c++  java
  • linux 汇编 函数调用

    Linux 汇编-函数调用

    GNU 汇编函数

    定义函数

    • 格式
    .type func_name, @function
    func_name:
    	#content
    ret
    
    • 注解

    .type 指令指定 func_name 为汇编程序调用此函数的地址

    fun_name 为函数名

    @function 表示函数内容开始

    ret 表示函数结束,返回到父函数调用子函数处

    调用函数

    • 格式
    call fun_name
    
    • 注解

    call 是调用子函数的汇编命令

    fun_name 是定义子函数时,.type 指定的函数地址

    编写汇编函数

    使用寄存器和全局变量传递函数参数

    即在主函数中先将数据保存到某寄存器,然后在函数中直接使用这个寄存器的指。

    # ASM function use register give the inut data
    .section .data
    	str:.ascii "ASM THIRD DAY\n"
    	sl=.-str
    
    .section .text
    .global _start
    _start:
    	movl $0, 	%eax		# Init eax
    	movl $2,  	%ebx		# Prepare data in ebx first
    
    	call 		add_fun		# Then call child function
    	
    	# System call: write()
    
    	movl $1, 	%ebx
    	movl $str, 	%ecx
    	movl $sl, 	%edx
    
    	int $0x80
    
    	movl $1, 	%eax
    	
    	# System call: exit
    	movl $0, 	%ebx
    	int $0x80 	
    
    # The method of GNU define a function
    .type add_fun, @function
    add_func:
    	add %ebx, 	%ebx
    	movl %ebx, 	%eax
    ret
    
    root@root:~# as fun_register.s -o fun.o
    root@root:~# ld fun.o -o fun
    root@root:~# .fun
    
    • 注解

    主程序中,movl $2, %ebx 将常量 2 赋值给寄存器 ebx, 为子函数 add_func 准备好数据。

    接下来调用子函数,使用 add 指令对寄存器 ebx 数据进行处理。

    通过全局变量给子函数传递数据,只需在数据段(.data 或者 .bss)定义变量,在主函数中初始化后在调用子函数来使用变量。

    在父函数调用子函数时,一定要符合子函数的需求:准备好要用到的寄存器和变量,准备好子函数输出结果的保存地址,同时主函数中也要直到函数输出保存的地址。

    使用 C 风格传参方式

    C 风格传参方式使用栈来给子函数准备数据,适合复杂的汇编程序

    只在栈顶发生操作,入栈的新栈顶,出栈移除当前栈顶元素,入栈 push,出栈 pop

    堆栈寄存器 esp 需要始终指向栈顶。

    ebp 用于保存栈基址。

    高地址内存叫栈底,低地址内存叫栈顶。

    入栈后,esp 值减小,即指向更小的地址。

    除使用 pushpop 指令外,还可操作栈地址来实现。通常将 esp 值拷贝到 ebp 来操作。

    • 通过栈为函数准备数据

    将子函数需要的数据存到栈里,需要保证存在栈里的数据与子函数使用的顺序相对应。

    注意: 当调用子函数时,系统会将当前地址压入栈中,当子函数执行完之后返回之前地址,以便程序继续执行。

    # Given data to child function by stack
    .section .data
    	str:.ascii "ASM FOURTH DAY\n"
    	sl=.-str
    
    .section .text
    .global _start
    _start:
    	push $4			# Be ready data for child func by stack
    	call give_value_to_eax
    
    	movl $1, 	%ebx	# System call: write()
    	movl $str, 	%ecx
    	movl $sl,	%edx
    	
    	int $0x80
    
    	movl $1, 	%eax	# System call exit
    	movl $0, 	%ebx
    	int $0x80
    
    # Child func
    .type give_value_to_eax, @function
    give_value_to_eax:
    	pushl %ebp		# Save ebp value
    	movl %esp, %ebp		# Get stack top address for ebp
    
    	movl 8(%ebp), %eax 	# eax's value is the bottom value of the stack
    
    	pop %ebp 			# Get the old ebp value again
    ret
    
    
    root@root:~# as fun_stack.s -o fun.o
    root@root:~# ld fun.o -o fun
    root@root:~# .fun
    
    • 注解

    主函数中,是两个系统调用代码。

    write 系统调用代码中,eax 的值通过子函数 give_value_to_eax 来赋予。

    在 give_value_to_eax 子函数中,使用在主函数中在栈中准备的数据来给 eax 赋值。因为压入栈中的还有当前调用函数的地址,因此使用 ebp 来访问原先压入栈中的数据。

    子函数中,第一行为备份 ebp 值,第二行将栈顶的 esp 值赋给 ebp,第三行通过 ebp 找到主函数为子函数准备的数据,并赋给 eax。

    使用 ebp 来获取 esp 值,然后通过 ebp 来访问栈中数据是为了保证 esp 一直指向栈顶。

     Program Stack
    +-------------------------+
    |                         |
    |                         | Indirect addresing
    |-------------------------|
    | Function parameter 3    | 16(%ebp)
    |-------------------------|
    | Function parameter 2    | 1(%ebp)
    |-------------------------|
    | Function parameter 1    | 8(%ebp)
    |-------------------------|
    | Return Address          | 4(%ebp)
    |-------------------------|
    | Old EBP Value           | (%ebp)  <----- ESP
    +-------------------------+
    

    函数末尾 pop %ebp 之后,栈顶就是 Return Address 了。

    当要用栈来存储函数内的局部变量时,只需要将 esp 继续开辟新的栈顶增加即可:

     Program Stack
    +-------------------------+
    |                         |
    |                         | Indirect addresing
    |-------------------------|
    | Function parameter 3    | 16(%ebp)
    |-------------------------|
    | Function parameter 2    | 1(%ebp)
    |-------------------------|
    | Function parameter 1    | 8(%ebp)
    |-------------------------|
    | Return Address          | 4(%ebp)
    |-------------------------|
    | Old EBP Value           | (%ebp)
    |-------------------------|
    | Local Variable 1        | -4(%ebp)
    |-------------------------|
    | Local Variable 2        | -8(%ebp)
    |-------------------------|
    | Local Variable 3        | -12(%ebp)  <---- ESP
    |-------------------------|
    |                         | 
    |-------------------------|
    |                         | 
    +-------------------------+
    
  • 相关阅读:
    svn_linux + apache 实现网页访问svn
    SVN_2008R2 搭建流程与规范
    mysql 简称
    论运维之故障排查思路与方法
    mac pro 基本使用
    防火墙之netfailt、iptables详解
    翻转单词顺序列(剑指offer)
    中缀变为后缀
    左旋转字符串(剑指offer)
    和为S的两个数字(剑指offer)
  • 原文地址:https://www.cnblogs.com/openxyz/p/6616123.html
Copyright © 2011-2022 走看看