博文
Jim Chan函数调用的汇编程序过程(2007-10-17 19:57:00)
摘要:Jim Chan
摘要:本文说明高级语言编译成汇编语言后,高级语言中函数调用的汇编程序过程。
正文:高级语言编译成汇编程序以后,在高级语言中的函数调用的汇编程序过程如下:
1.将函数参数入栈,第一个参数在栈顶,最后一个参数在栈底。
2.执行CALL指令,调用该函数,进入该函数代码空间。
a.执行CALL指令,将CALL指令下一行代码的地址入栈。
b.进入函数代码空间后,将基址指针EBP入栈,然后让基址指针EBP指向当前堆栈栈顶,并使用它访问存在堆栈中的函数输入参数及堆栈中的其他数据。
c.堆栈指针ESP减少一个值,如44H,向上移动一个距离,留出一个空间给该函数作为临时存储区。
{
// 以上准备工作做好后,函数正式被执行,如下所示。
d.将其他指针或寄存器中的值入栈,以便在函数中使用这些寄存器。
e.执行代码。
f.执行return()返回执行结果,将要返回的值存入EAX中。
g.步骤2.d中的指针出栈。
}
h.将EBP的值传给堆栈指针ESP,使ESP复原为2.c之前的值。此时进入函数时EBP的值在栈顶。
i.基址指针EBP出栈,复原为2.b之前的EBP的值。
j.执行RET指令,“调用函数”的地址出栈,本函数返回到CALL指令的下一行。
3.函数返回到CALL指令下一行,将堆栈指针加一个数值,以使堆栈指针恢复到以上步骤1执行之前的值。该数值是上面第一步入栈参数的总长度。
注意:
1.堆栈指针ESP指向栈顶的新入栈数据的最低位。
2.MOV指令中偏移指针指向被“MOV”的数据的最低位。如下面指令是将ebp+8到ebp+11四个字节的内容传到eax寄存器中。
00402048 mov eax,dword ptr [ebp+8]
一个例子如下:
高......
函数调用时堆栈的使用(2007-10-17 19:24:00)
摘要:在经典的汇编语言教程中,函数调用时堆栈的使用都是着重讲解的问题。如今随着高级语言的越来越完善,单纯使用汇编开发的程序已经不多了。但对函数调用时堆栈动向的了解仍有助于我们明晰程序的执行流程,从而在程序编写和调试的过程中有一个清晰的思路。
一.调用约定
在Win32中,有关函数的调用主要有两种约定。
1._stdcall
以__stdcall方式调用的函数有以下特征:
? 参数由右至左压栈
? 调用返回时,堆栈由被调函数调整
2.__cdecl
__cdecl约定是C/C++函数的默认调用约定。它有以下特征:
? 参数由右至左压栈
? 调用返回时,堆栈由调用者调整
二.Win32函数调用过程
1. 压入参数
这里依据以上的调用方式将调用者给出的参数一一压入堆栈。
2. 压入断点
当程序执行到Call指令的时候,当前语句的地址作为断点地址压入堆栈。
3. 跳转
eip的值被重新设置为被调函数的起始地址。
4. mov ebp, esp
这里ebp被用来在堆栈中寻找调用者压入的参数,同时作为调用者堆栈指针的一个备份。在此前还应该执行一条:
push ebp
把ebp中原来的数值保存。
5. sub esp,N
这里N是函数内局部变量的总字节数加上一个整数,一般为40。此后esp即为被调函数的堆栈指针了。
6. 初始化esp ~ esp-N之间的N字节空间
这是对堆栈中已分配给局部变量使用的内存空间的初始化,一般全部设置为0xcc。
7. 顺序执行函数内语句。
此时函数的堆栈位于所有局部变量的内存空间之后,二者之间一般有40字节的隔离带。
8.返回
为保障调用的正常返回,函数内应当保证规范使用堆栈,使即将返回的时候esp的值恢复为执行第一条语句前的状态。说明白点,就是每一条push都要有相应的pop。
调用返回的过程如下:
mov esp, ebp
执行后,esp恢复为调用者的堆栈指针,栈顶除断点地址外,还存有原e......
Win32 环境下的堆栈 选择自 slimak 的 Blog (2007-10-17 19:15:00)
摘要:Win32 环境下的堆栈(一)
简介
在Win32环境下利用调试器调试应用程序的时候经常要和堆栈(Stack)打交道,尤其是在需要手工遍历堆栈(Manually Walking Stack)的时候我们需要对堆栈的工作过程有一个比较清晰的了解.接下来的这些文字将通过一个例子程序详细的讲解堆栈的工作过程.
关键字
调试 堆栈 Stack Stack-Frame
目录
1.堆栈是什么?
2.堆栈里面放的都是什么信息?
3.堆栈是在什么时候被建立起来的?它的默认大小是多少?
4.默认才1M??那要是我的程序使用超过了1M的堆栈怎么办?
5.什么叫Stack Frame?
6.在一次函数调用中,堆栈是如何工作的?
7.老大,结合一个例子讲讲吧?
1.堆栈是什么?
从内存管理角度看,堆栈是就是一块连续的内存空间,对它的操作采用先入后出的规则,他的生长方向与内存的生长方向正好相反,也就是说它是从高地址向低地址生长.
从Win32程序内部的角度看,每一个线程有自己的堆栈,它主要用来给线程提供一个暂时存放数据的区域,程序使用POP/PUSH指令来对堆栈进行操作.
2.堆栈里面放的都是什么信息?
堆栈中存放的信息包括:当前正在执行的函数的局部变量,函数返回地址,该函数的上层函数传给该函数的参数,EBP的值,一些通用寄存器(EDI,ESI…)的值,注意这里提到的正在执行的函数,比如有下面的一段C代码:
void B()
{
printf(“B\n”);
}
void A()
{
B();
}
那么当程序执行到B函数的pri......
6.3 正确的尾调用(原文:Proper Tail Calls)(2007-10-17 19:00:00)
摘要:6.3 正确的尾调用(原文:Proper Tail Calls)
Lua中函数的另一个有趣的特征是可以正确的处理尾调用.(一些作者使用术语尾递归[原文:proper tail recursion],虽然并未涉及到递归的概念) .
尾调用是一种类似在函数结尾的goto调用,当函数最后一个动作是调用另外一个函数时,我们称这种调用尾调用.例如:
function f (x)
return g(x)
end
g的调用是尾调用.
例子中f调用g后不会再做任何事情,这种情况下当被调用函数g结束时程序不需要返回到调用者f;所以尾调用之后程序不需要在栈中保留关于调用者的任何信息.一些编译器比如Lua解释器利用这种特性在处理尾调用时不使用额外的栈,我们称这种语言支持正确的尾调用.
由于尾调用不需要使用栈空间,那么尾调用递归的层次可以无限制的.例如下面调用不论n为何值不会导致栈溢出.
function foo (n)
if n > 0 then return foo(n - 1) end
end
需要注意的是:明确什么是尾调用.
一些调用者函数调用其他函数后也没有做其他的事情但不属于尾调用.比如:
function f (x)
g(x)
return
end
上面这个例子中f在调用g后,不得不丢弃g地返回值,所以不是尾调用,同样的下面几个例子也不时尾调用:
return g(x) + 1 -- must do the addition
return x or g(x) -- must adjust to 1 result
return (g(x)) &n......
QK(2007-10-12 19:37:00)
摘要:// Death Coil
[AUdc]
Tip=Death |cffffcc00C|roil - [|cffffcc00Level 1|r],Death |cffffcc00C|roil - [|cffffcc00Level 2|r],Death |cffffcc00C|roil - [|cffffcc00Level 3|r]
Hotkey=W
Researchtip="Learn Death |cffffcc00C|roil - [|cffffcc00Level %d|r]"
Researchhotkey=W
// Unholy Aura
[AUau]
Tip=Unholy Aura - [|cffffcc00Level 1|r],Unholy Aura - [|cffffcc00Level 2|r],Unholy Aura - [|cffffcc00Level 3|r]
Researchtip="Learn |cffffcc00U|rnholy Aura - [|cffffcc00Level %d|r]"
Researchhotkey=Q
// Frost Nova
[AUfn]
Tip=Frost |cffffcc00N|rova - [|cffffcc00Level 1|r],Frost |cffffcc00N|rova - [|cffffcc00Level 2|r],Frost |cffffcc00N|rova - [|cffffcc00Level 3|r]
Hotkey=W
Researchtip="Learn Frost |cffffcc00N|rova - [|cffffcc00Level %d|r]"
Researchhotkey=W
// Frost Armor (Autocast, Lich)
[AUfu]
Tip=|cffffcc00F|rrost Armor - [|cffffcc00Level 1|r],|cffffcc00F|rrost Armor - [|cffffcc00Level 2|r],|cffffcc00F|rrost Armor - [|cffffcc00Level 3|r]
Untip="|cffc3dbffRi......
循环队列的基本操作(2007-09-08 16:46:00)
摘要:#define maxsize 5
#include <stdio.h>
#include <alloc.h>
typedef struct{
int data[maxsize];
int front;
int rear;
}SqQueue;
void InitQueue(SqQueue *&q)
{
q=(SqQueue*)malloc(sizeof(SqQueue));//有志向拉
q->front=q->rear=0;
}
void ClearQueue(SqQueue *&q)
{
free(q);
}
int EnQueue(SqQueue *&q,int &e)
{
if((q->rear+1)%maxsize==q->front)
{
printf("队列满了\n",e);
return 0;//队满
}
q->rear=(q->rear+1)%maxsize;
q->data[q->rear]=e;
return 1;
}
int ouQueue(SqQueue *&q,int &e)
{
if((q->rear==q->front))
{
printf("队列为空\n",e);
return 0;//队空
}
q->front=(q->front+1)%maxsize;
e=q->data[q->front];
printf("出队元素是%d\n",e);
return 1;
}
void Show(SqQueue *&q)
{
int i=0;
堆栈的基本操作(2007-09-08 14:37:00)
摘要:#define STACK_INIT_SIZE 3
#define STACK_INCREAMENT 2
#define null 0
#include <stdio.h>
#include <alloc.h>
typedef struct stack{
int *base;
int *top;
int size;//当前已非配的空间,没数据也算
}Sqstack;//用作堆栈的指针de 类型
void Initstack(Sqstack &s)//建立堆栈
{
s.base=(int*)malloc(STACK_INIT_SIZE*sizeof(int));
if(s.base==null)
{
printf("overflow");
}
s.top=s.base;
s.size=STACK_INIT_SIZE;
}
void Gettop(Sqstack &s,int &e)
{
if(s.top==s.base){printf("stack is empty");}
e=*(s.top-1);//注意哦,有一个元素时top指向第二隔了,没改变TOP的指向
}
void Push(Sqstack &s,int e)
{
if((s.top-s.base)+1==s.size)//堆栈满了
{
s.base=(int*)realloc(s.base,(s.size+STACK_INCREAMENT)*sizeof(int));
打印斜下三角形(2007-09-08 14:35:00)
摘要:int max=10;
int a[10][10]={0};
int i,j,t,q=0,s=0,n=max ;
for(;n>0;n--)
{
s=s+n;
}
for(t=1,i=0,j=0;t<s+1;t++)
{
a[i][j]=t;
i++;
j++;
if(i==max)
{
j=0;
q=q+1;
i=q;
}
}
for(i=0;i<max;i++)
{
for(j=0;j<i+1;j++)
{printf("%d ",a[i][j]);}
printf("\n");
}
......
Stein算法--转bpttc的发言(2007-04-20 12:23:00)
摘要:转自http://www.programfan.com/club/showbbs.asp?id=227318&page=1
bpttc的发言
int GCD_Stein( int x, int y )
{
int factor = 0;
int temp;
if ( x < y )
{
temp = x;
x = y;
y = temp;
}
while ( x != y )
{<......
c#作业(2007-04-18 21:32:00)
摘要:using System;
namespace studywork2
{
public class work
{
public static void sumjiecheng()
{
long n = 1, t = 1, s = 0;
for (; n <= 20; n++)
{
t *= n;
s += t;
}
Console.WriteLine("1到20的阶乘之和为:");
Console.WriteLine(s);
&n......