linux 汇编

Linux 汇编-函数调用

html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video { margin: 0; padding: 0; border: 0 }body { font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14px; line-height: 1.6; color: #333; background-color: #fff; padding: 20px; max-width: 960px; margin: 0 auto }body>*:first-child { margin-top: 0 !important }body>*:last-child { margin-bottom: 0 !important }p,blockquote,ul,ol,dl,table,pre { margin: 15px 0 }h1,h2,h3,h4,h5,h6 { margin: 20px 0 10px; padding: 0; font-weight: bold }h1 tt,h1 code,h2 tt,h2 code,h3 tt,h3 code,h4 tt,h4 code,h5 tt,h5 code,h6 tt,h6 code { font-size: inherit }h1 { font-size: 28px; color: #000 }h2 { font-size: 24px; border-bottom: 1px solid #ccc; color: #000 }h3 { font-size: 18px }h4 { font-size: 16px }h5 { font-size: 14px }h6 { color: #777; font-size: 14px }body>h2:first-child,body>h1:first-child,body>h1:first-child+h2,body>h3:first-child,body>h4:first-child,body>h5:first-child,body>h6:first-child { margin-top: 0; padding-top: 0 }a:first-child h1,a:first-child h2,a:first-child h3,a:first-child h4,a:first-child h5,a:first-child h6 { margin-top: 0; padding-top: 0 }h1+p,h2+p,h3+p,h4+p,h5+p,h6+p { margin-top: 10px }a { color: #4183C4; text-decoration: none }a:hover { text-decoration: underline }ul,ol { padding-left: 30px }ul li>:first-child,ol li>:first-child,ul li ul:first-of-type,ol li ol:first-of-type,ul li ol:first-of-type,ol li ul:first-of-type { margin-top: 0px }ul ul,ul ol,ol ol,ol ul { margin-bottom: 0 }dl { padding: 0 }dl dt { font-size: 14px; font-weight: bold; font-style: italic; padding: 0; margin: 15px 0 5px }dl dt:first-child { padding: 0 }dl dt>:first-child { margin-top: 0px }dl dt>:last-child { margin-bottom: 0px }dl dd { margin: 0 0 15px; padding: 0 15px }dl dd>:first-child { margin-top: 0px }dl dd>:last-child { margin-bottom: 0px }pre,code,tt { font-size: 12px; font-family: Consolas, “Liberation Mono”, Courier, monospace }code,tt { margin: 0 0px; padding: 0px 0px; white-space: nowrap; border: 1px solid #eaeaea; background-color: #f8f8f8 }pre>code { margin: 0; padding: 0; white-space: pre; border: none; background: transparent }pre { background-color: #f8f8f8; border: 1px solid #ccc; font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px }pre code,pre tt { background-color: transparent; border: none }kbd { background-color: #DDDDDD; background-image: linear-gradient(#F1F1F1, #DDDDDD); background-repeat: repeat-x; border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD; border-style: solid; border-width: 1px; font-family: “Helvetica Neue”, Helvetica, Arial, sans-serif; line-height: 10px; padding: 1px 4px }blockquote { border-left: 4px solid #DDD; padding: 0 15px; color: #777 }blockquote>:first-child { margin-top: 0px }blockquote>:last-child { margin-bottom: 0px }hr { clear: both; margin: 15px 0; height: 0px; overflow: hidden; border: none; background: transparent; border-bottom: 4px solid #ddd; padding: 0 }table th { font-weight: bold }table th,table td { border: 1px solid #ccc; padding: 6px 13px }table tr { border-top: 1px solid #ccc; background-color: #fff }table tr:nth-child(2n) { background-color: #f8f8f8 }img { max-width: 100% }GNU 汇编函数定义函数格式

.type func_name, @functionfunc_name:#contentret

注解

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

fun_name 为函数名

@function 表示函数内容开始

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

调用函数格式

call fun_name

注解

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

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

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

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

# ASM function use register give the inut data.section .datastr:.ascii "ASM THIRD DAY\n"sl=.-str.section .text.global _start_start:movl $0, %eax# Init eaxmovl $2,  %ebx# Prepare data in ebx firstcall add_fun# Then call child function# System call: write()movl $1, %ebxmovl $str, %ecxmovl $sl, %edxint $0x80movl $1, %eax# System call: exitmovl $0, %ebxint $0x80 # The method of GNU define a function.type add_fun, @functionadd_func:add %ebx, %ebxmovl %ebx, %eaxret
root@root:~# as fun_register.s -o fun.oroot@root:~# ld fun.o -o funroot@root:~# .fun

注解

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

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

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

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

使用 C 风格传参方式

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

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

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

ebp 用于保存栈基址。

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

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

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

通过栈为函数准备数据

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

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

# Given data to child function by stack.section .datastr:.ascii "ASM FOURTH DAY\n"sl=.-str.section .text.global _start_start:push $4# Be ready data for child func by stackcall give_value_to_eaxmovl $1, %ebx# System call: write()movl $str, %ecxmovl $sl,%edxint $0x80movl $1, %eax# System call exitmovl $0, %ebxint $0x80# Child func.type give_value_to_eax, @functiongive_value_to_eax:pushl %ebp# Save ebp valuemovl %esp, %ebp# Get stack top address for ebpmovl 8(%ebp), %eax # eax's value is the bottom value of the stackpop %ebp # Get the old ebp value againret
root@root:~# as fun_stack.s -o fun.oroot@root:~# ld fun.o -o funroot@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|-------------------------||                         | |-------------------------||                         | +-------------------------+

做事不怕难,自无难人事。

linux 汇编

相关文章:

你感兴趣的文章:

标签云: