1.判断运行时环境
第一步骤是从你的编译器获得一个汇编语言代码列表。
1)测试程序
2)静态变量和初始化
3)堆栈帧
一个函数分成三个部分:函数序、函数体、函数跋。
4)寄存器变量
5)外部标识符的长度
6)判断堆栈帧布局
运行时堆栈保存了每个函数运行时所需要的数据,包括它的自动变量和返回地址。
a.传递函数参数
b.函数序
c.堆栈中的参数次序
d.最终的堆栈帧布局
e.函数跋
f.返回值
g.表达式的副作用
2.C和汇编语言的接口
编写能够调用C程序或者被C程序调用的汇编语言程序所需的内容。与这个环境相关的结果总结如下--你的环境肯定在某些方面与它不同!
首先,汇编程序中的名字必须遵循外部标识符的规则。
其次,汇编程序必须遵循正确的函数调用/返回协议。有两种情况:从一个汇编语言程序调用一个C程序和从一个程序调用一个汇编程序。为了从汇编程序调用C程序:
1)如果寄存器d0、d1、a0或a1保存了重要的值,它们必须在调用C程序之前进行保存,因为C函数不会保存它们的值。
2)任何函数的参数必须以参数列表相反的顺序压入到堆栈中。
3)函数必须由一条“跳转子程序”类型的指令调用,它会把返回地址压入到堆栈中。
4)当C函数返回时,汇编程序必须清除堆栈中的任何参数。
5)如果汇编程序期望接受一个返回值,它将保持在d0(如果返回值的类型为double,它的另一半将位于d1)。
6)任何在调用之前进行过保存的寄存器此时可以恢复。
为了编写一个由C程序调用的汇编程序:
1)保存任何你希望修改的寄存器(除d0、d1、a0或a1之外)。
2)参数值从堆栈中获得,因为调用它的C函数把参数压入到堆栈中。
3)如果函数应该返回一个值,它的值应该保存在d0中(在这种情况下,d0不能进行保存和恢复)。
4)在返回之前,函数必须清除任何它压入到堆栈中的内容。
3.运行时效率
即使在一些现代的机器上,一个必须存储于ROM的程序必须相当小才有可能装入到有限的内存空间中。但许多现代计算机系统在这方面的限制大不如前,这是因为它们提供了**虚拟内存。虚拟内存是由操作系统实现的,它在需要时把程序活动部分放入内存并把不活动的部分复制到磁盘中**,这样就允许系统运行大型的程序。但程序越大,需要进行的复制就越多。所以大型程序不是想以前那样根本无法运行,而是随着程序的增大,它的执行效率逐渐降低。
如果一个程序太大或太慢,较之专研每个变量,看看把它们声明为register能不能提高效率,选一种效率更高的算法或数据结构往往效果要满意得多。然而这并不是说你可以在代码中胡作非为,因为风格恶劣的代码总是会把事情弄得更糟。
如果一个程序太大,很容易想到的着手方向:最大的函数和数据结构。
如果程序太慢,着手方向:对程序进行性能测评,花费时间最多的部分程序和使用最频繁的那部分代码显然是需要优化的目标。如果这方面能够提升,将能大大提高程序的整体运行速度。
三个努力方向:
1)在耗时最多的函数中,有些是库函数。如果能减少或不用可帮助大大提升性能。
2)有效函数之所以耗费了大量的时间是因为它们被调用的**次数非常多**。
3)有些函数调用次数不多,但每次调用耗费时间却很长。寻找更优质的算法重构是努力的方向。
4)可以对单个函数进行汇编语言重新编码,函数越小,重新编码越容易。
4.总结
绝大多数环境都创建某种类型的堆栈帧,函数用它来保存它们的数据,堆栈帧的细节可能各不相同,但它们的基本思路是相当一致的。
提高效率的最好方法是为它选择一种更好的算法,接下来的一种提高程序执行速度的最佳手段是对程序进行性能测评,看看程序在哪个地方花费的时间最多,把优化措施集中在程序的这部分将产生最好的结果。
5.警告总结
1)是链接器而不是编译器决定外部标识符的最大长度;
2)你无法链接由不同编译器产生的程序;
6.编程提示的总结
1)使用stdarg实现可变参数列表;
2)改进算法比优化代码更有效率;
3)使用某种环境特有的技巧会导致程序不可移植。