Assembly 可重入和递归子程序
一个可重入子程序必须满足下面几个性质:
1、它不能修改代码指令。在高级语言中,修改代码指令是非常难的;但是在汇编语言中,一个程序要修改自己的代码并不是一件很难的事。
例如:
mov word [cs:$+7], 5 ; 将5复制到前面七个字节的字中
add ax, 2 ; 前面的语句将2改成了5!
这些代码在实模式下可以运行,但是在保护模式下的操作系统上不行,因为代码段被标识为只读。在这些操作系统上,当执行了上面的第一行代码,程序将被终止。这种类型的程序从各个方面来看都非常差。它很混乱,很难维护而且不允许代码共享(看下面)。
2、它不能修改全局变量(比如在data和bss段里的数据)。所有的变量应储存在堆栈里。
书写可重入性代码有几个好处。
1、一个可重入子程序可以递归调用。
2、 一个可重入程序可以被多个进程共享。在许多多任务操作系统上,如果一个程序有许多实例正在运行,那么只有一份代码的拷贝在内存中。共享库和DLL(Dynamic Link Libraries,动态链接库)同样使用了
这种技术。
3、可重入子程序可以运行在多线程5 程序中。Windows 9x/NT和大多数类UNIX操作系统(Solaris,Linux,等)都支持多线程程序。
递归子程序
例如:子程序foo可以调用bar且bar也可以调用foo。
递归子程序必须有一个终止条件。当这个条件为真时,就不再进行递归调用了。如果一个子程序没有终止条件或条件永不为真,那么递归将不会结束(非常像一个无穷循环)。
图4.15展示了一个递归求n!的函数。在C中它可以这样被调用:
图4.16展示了上面的函数调用的最深点的堆栈状态。
回顾一下C变量的储存类型
automatic,自动 它是定义在一个函数内的C变量的缺省类型。当定义它们的函数被调用了,这些变量就被分配在堆栈上,而当函数返回了又从堆栈中移除。因此,它们没有固定的内存空间。
volatile,不稳定 这个关键字告诉编译器这个变量值随时都会改变。这就意味着当变量被更改了,编译器不能做出任何推断。通常编译器会将一个变量的值暂时存在寄存器中,而且在出现这个变量的代码部分使
用这个寄存器。但是,编译器不能对不稳定类型的变量做这种类型的优化。一个不稳定变量的最普遍的例子就是:它可以被多线程程序的两个线程修改。考虑下面的代码:
2 y = 20;
3 z = x;
更多建议: