HTML5技术

Java Main如何被执行? - iceAeterna(2)

字号+ 作者:H5之家 来源:博客园 2015-11-05 10:22 我要评论( )

main:pushq %rbp // 保存rbp .seh_pushreg % rbpmovq %rsp, %rbp // 更新栈基址 .seh_setframe %rbp, 0 subq $ 80 , % rsp.seh_stackalloc .seh_endprologuecall __mainmovabsq $ 4611686018427387904 , %rdx // 0x

main: pushq %rbp //保存rbp .seh_pushreg %rbp movq %rsp, %rbp //更新栈基址 .seh_setframe %rbp, 0 subq $80, %rsp .seh_stackalloc .seh_endprologue call __main movabsq $4611686018427387904, %rdx //0x4000000000000000,即浮点数2.0 movabsq $4613937818241073152, %rax //0x3000000000000000,即浮点数3.0 movq %rax, 32(%rsp) //第5个参数3.0,即param_d2保存在栈空间上 movl $3, %r9d //第4个参数3,即param_i2保存在r9d中(r9的低32位) movq %rdx, -24(%rbp) movsd -24(%rbp), %xmm2 //第3个参数2.0,即param_d1保存在xmm2中 movss .LC2(%rip), %xmm1 //第2个参数1.0(0x3f800000),保存在xmm1中 movl $1, %ecx //第1个参数1,保存在ecx中(rcx的低32位) call func

func函数返回后,main函数将从xmm0中取出返回结果

call func movq %xmm0, %rax //保存结果 movq %rax, -8(%rbp) movl $0, %eax //清空eax,回收main栈,恢复栈顶地址 addq $80, %rsp popq %rbp ret

func函数的栈和操作数准备如下:

func: pushq %rbp //保存rbp(main函数栈的基址) .seh_pushreg %rbp movq %rsp, %rbp //将main栈的栈顶指针作为被调用函数的栈基址 .seh_setframe %rbp, 0 subq $32, %rsp //func栈需要32字节的栈空间 .seh_stackalloc 32 .seh_endprologue movl %ecx, 16(%rbp) //将4个参数移动到栈底偏移16-40的空间(main栈的shadow space) movss %xmm1, 24(%rbp) movsd %xmm2, 32(%rbp) movl %r9d, 40(%rbp) movabsq $4613937818241073152, %rax //本地变量local_d2,即浮点数3.0 movq %rax, -8(%rbp) //5个局部变量 movl 16(%rbp), %eax movl %eax, -12(%rbp) movl 40(%rbp), %eax movl %eax, -16(%rbp) movl 24(%rbp), %eax movl %eax, -20(%rbp) movq 32(%rbp), %rax movq %rax, -32(%rbp)

随后的func的运算过程如下:

   movl -16(%rbp), %eax //local_i2 - local_i1 subl -12(%rbp), %eax pxor %xmm0, %xmm0 //准备xmm0寄存器,按位异或,xmm0清零 cvtsi2ss %eax, %xmm0 mulss -20(%rbp), %xmm0 //local_f1 * (local_i2 - local_i1) cvtss2sd %xmm0, %xmm0 addsd -32(%rbp), %xmm0 //local_d1 + local_f1 * (local_i2 - local_i1) subsd 48(%rbp), %xmm0 //local_d1 + local_f1 * (local_i2 - local_i1) - param_d2 addsd -8(%rbp), %xmm0 //local_d1 + local_f1 * (local_i2 - local_i1) - param_d2 + local_d2 addq $32, %rsp //回收func栈,恢复栈顶地址 popq %rbp ret

根据以上代码分析,大概得出该程序调用栈结构:

这里没有考虑func函数再次调用其他函数而准备操作数的栈内容的情况,但结合main函数栈,大致可以得出栈的通用结构如下: 

call_stub由generate_call_stub()解释成汇编代码,有兴趣的可以继续阅读call_stub的汇编代码进行分析。 
下面对call_stub的汇编部分进行分析: 
先来看下call_stub的调用栈结构:(注:本文实验是在windows_64位平台上实现的)

// Call stubs are used to call Java from C // return_from_Java 是紧跟在call *%eax后面的那条指令的地址 // [ return_from_Java ] <--- rsp // -28 [ arguments ] <-- rbp - 0xe8 // -26 [ saved xmm15 ] <-- rbp - 0xd8 // -24 [ saved xmm14 ] <-- rbp - 0xc8 // -22 [ saved xmm13 ] <-- rbp - 0xb8 // -20 [ saved xmm12 ] <-- rbp - 0xa8 // -18 [ saved xmm11 ] <-- rbp - 0x98 // -16 [ saved xmm10 ] <-- rbp - 0x88 // -14 [ saved xmm9 ] <-- rbp - 0x78 // -12 [ saved xmm8 ] <-- rbp - 0x68 // -10 [ saved xmm7 ] <-- rbp - 0x58 // -9 [ saved xmm6 ] <-- rbp - 0x48 // -7 [ saved r15 ] <-- rbp - 0x38 // -6 [ saved r14 ] <-- rbp - 0x30 // -5 [ saved r13 ] <-- rbp - 0x28 // -4 [ saved r12 ] <-- rbp - 0x20 // -3 [ saved rdi ] <-- rbp - 0x18 // -2 [ saved rsi ] <-- rbp - 0x10 // -1 [ saved rbx ] <-- rbp - 0x8 // 0 [ saved rbp ] <--- rbp, // 1 [ return address ] <--- rbp + 0x08 // 2 [ ptr. to call wrapper ] <--- rbp + 0x10 // 3 [ result ] <--- rbp + 0x18 // 4 [ result_type ] <--- rbp + 0x20 // 5 [ method ] <--- rbp + 0x28 // 6 [ entry_point ] <--- rbp + 0x30 // 7 [ parameters ] <--- rbp + 0x38 // 8 [ parameter_size ] <--- rbp + 0x40 // 9 [ thread ] <--- rbp + 0x48

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 如何快速处理线上故障 - 倒骑的驴

    如何快速处理线上故障 - 倒骑的驴

    2017-05-02 12:01

  • 如何在 ASP.NET Core 中发送邮件 - Savorboard

    如何在 ASP.NET Core 中发送邮件 - Savorboard

    2017-05-02 08:02

  • 对于Bootstrap的介绍以及如何使用 - novai-L

    对于Bootstrap的介绍以及如何使用 - novai-L

    2017-04-29 09:00

  • 谈一下我们是如何开展code review的 - HarlanC

    谈一下我们是如何开展code review的 - HarlanC

    2017-04-27 15:03

网友点评