算是把math模块读了个大概了,已经可以着手把该记录的写下来了。
总体来讲,math结构简单便于理解,而且它本身与系统之间的耦合度很低,所以我们可以把更多的时间花在知识点的学习上面。直白的说,这个模块非常独立,完全超出了你的预期!
一 结构体
I. struct info
struct info {
long ___math_ret;
long ___orig_eip;
long ___edi;
long ___esi;
long ___ebp;
long ___sys_call_ret;
long ___eax;
long ___ebx;
long ___ecx;
long ___edx;
long ___orig_eax;
long ___fs;
long ___es;
long ___ds;
long ___eip;
long ___cs;
long ___eflags;
long ___esp;
long ___ss;
};
我们可以结合device_not_available(sys_call.s)中断来理解它。构造出该结构体的意义在于简单方便地管理栈数据,比如通过info.___eip知道用户程序执行到了哪条指令等。
II. struct i387_struct
struct i387_struct {
long cwd; /* 控制寄存器,16bit */
long swd; /* 状态寄存器,16bit */
long twd; /* 标志寄存器,16bit */
long fip; /* 浮点指令地址偏移,32bit */
long fcs; /* 代码段,16bit + 浮点指令操作码12bit */
long foo; /* 操作数地址偏移,32bit */
long fos; /* 数据段,16bit */
long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
};
III. struct swd
struct swd {
int ie:1; /* 8.5.1 Invalid operation exception */
int de:1; /* 8.5.2 Denormal operand exception (#D) */
int ze:1; /* 8.5.3 Divide-by-zero exception (#Z) */
int oe:1; /* 8.5.4 Numeric overflow exception (#O) */
int ue:1; /* 8.5.5 Numeric underflow exception (#U) */
int pe:1; /* 8.5.6 Inexact-result (Precision) exception (#P) */
int sf:1; /* Stack fault */
int ir:1; /* Error summary status */
int c0:1; /* Condition code */
int c1:1;
int c2:1;
int top:3; /* Top of stack pointer */
int c3:1;
int b:1; /* FPU Busy */
};
IV. data struct
typedef struct {
long a,b;
short exponent;
} temp_real;
typedef struct {
short m0,m1,m2,m3;
short exponent;
} temp_real_unaligned;
typedef struct {
long a,b;
} long_real;
typedef long short_real;
typedef struct {
long a,b;
short sign;
} temp_int;
- temp_real:浮点处理器内部数据寄存器格式(扩展的双精度实数/临时实数)
- temp_real_unaligned:为了能够真实对齐拷贝正确的内容的浮点处理器内部数据寄存器格式,我们来详细说一下它,顺便把Linus说的一段脏话撩出来
/*
* Gcc forces this stupid alignment problem: I want to use only two longs
* for the temporary real 64-bit mantissa, but then gcc aligns out the
* structure to 12 bytes which breaks things in math_emulate.c. Shit. I
* want some kind of "no-alignt" pragma or something.
*/
大概意思就是说GCC编译器把temp_real格式对齐成了12个byte,所以他不得不重新构造一种所谓的“no-alignt”的格式,这是因为临时实数为10个byte,可能你还是没有理解,没关系,我们来看看浮点处理器内部数据寄存器怎么存储的。
i387_struct结构体里面有个数组成员st_space,类型为long,数组大小为20,刚好80个byte,存储着R0~R7这8个数据寄存器,因此如果我们用temp_real来进行拷贝操作的话,这样会把第11、12字节覆盖掉,这是错误的,因为数据寄存器只有10个byte。
- long_real:双精度实数格式
- short_real:单精度实数格式
- temp_int:临时整数格式
二 浮点常量
#define CONSTZ (temp_real_unaligned) {0x0000,0x0000,0x0000,0x0000,0x0000}
#define CONST1 (temp_real_unaligned) {0x0000,0x0000,0x0000,0x8000,0x3FFF}
#define CONSTPI (temp_real_unaligned) {0xC235,0x2168,0xDAA2,0xC90F,0x4000}
#define CONSTLN2 (temp_real_unaligned) {0x79AC,0xD1CF,0x17F7,0xB172,0x3FFE}
#define CONSTLG2 (temp_real_unaligned) {0xF799,0xFBCF,0x9A84,0x9A20,0x3FFD}
#define CONSTL2E (temp_real_unaligned) {0xF0BC,0x5C17,0x3B29,0xB8AA,0x3FFF}
#define CONSTL2T (temp_real_unaligned) {0x8AFE,0xCD1B,0x784B,0xD49A,0x4000}
/*
V = (-1)^s x M x 2^E, s为0或1,M为大于等于1小于2的数,E为指数,令偏置数为basic=2^14-1
0.0 = (-1)^0 x 0.0 x 2^0
1.0 = (-1)^0 x 1.0 x 2^(0+basic)
PI = 3.1415926535897932384626433832795
LN2 = loge(2) = .69314718055994530941723212145818
LG2 = log10(2) = .30102999566398119521373889472449
L2E = log2(e) = 1.4426950408889634073599246810019
L2T = log2(10) = 3.3219280948873623478703194294894
*/
我们可以将这些浮点数转换为临时实数,首先对整数和小数部分分别处理成二进制,然后在转换为临时实数格式
整数部分:an*2^n + a(n-1)*2^(n-1) + ...+ a0*2^0
小数部分:an*(1/2)^n + a(n-1)*(1/2)^(n-1) + ... + a1*(1/2)^1
三 重要函数
I. math_abort
void __math_abort(struct info *, unsigned int);
#define math_abort(x,y) \
(((volatile void (*)(struct info *,unsigned int)) __math_abort)((x),(y)))
II. ea.c
char * ea(struct info * __info, unsigned short __code);
- ea:获取操作数地址
III. convert.c
void short_to_temp(const short_real * __a, temp_real * __b);
void long_to_temp(const long_real * __a, temp_real * __b);
void temp_to_short(const temp_real * __a, short_real * __b);
void temp_to_long(const temp_real * __a, long_real * __b);
void real_to_int(const temp_real * __a, temp_int * __b);
void int_to_real(const temp_int * __a, temp_real * __b);
- short_to_temp:单精度实数转换为临时实数
- long_to_temp:双精度实数转换为临时实数
- temp_to_short:临时实数转换为单精度实数
- temp_to_long:临时实数转换为双精度实数
- real_to_int:临时实数转换为临时整数
- int_to_real:临时整数转换为临时实数
IV. get_put.c
void get_short_real(temp_real *, struct info *, unsigned short);
void get_long_real(temp_real *, struct info *, unsigned short);
void get_temp_real(temp_real *, struct info *, unsigned short);
void get_short_int(temp_real *, struct info *, unsigned short);
void get_long_int(temp_real *, struct info *, unsigned short);
void get_longlong_int(temp_real *, struct info *, unsigned short);
void get_BCD(temp_real *, struct info *, unsigned short);
void put_short_real(const temp_real *, struct info *, unsigned short);
void put_long_real(const temp_real *, struct info *, unsigned short);
void put_temp_real(const temp_real *, struct info *, unsigned short);
void put_short_int(const temp_real *, struct info *, unsigned short);
void put_long_int(const temp_real *, struct info *, unsigned short);
void put_longlong_int(const temp_real *, struct info *, unsigned short);
void put_BCD(const temp_real *, struct info *, unsigned short);
- get/put_short_real:load/store单精度实数(m32r)
- get/put_long_real:load/store双精度实数(m64r)
- get/put_temp_real:load/store临时实数(m80r)
- get/put_short_int:load/store短整数(m16j)
- get/put_long_int:load/store整数(m32j)
- get/put_longlong_int:load/store长整数(m64j)
V. compute
/* add.c */
void fadd(const temp_real *, const temp_real *, temp_real *);
/* mul.c */
void fmul(const temp_real *, const temp_real *, temp_real *);
/* div.c */
void fdiv(const temp_real *, const temp_real *, temp_real *);
/* compare.c */
void fcom(const temp_real *, const temp_real *);
void fucom(const temp_real *, const temp_real *);
void ftst(const temp_real *);
- fadd, fmul, fdiv:加法,乘法,除法
- fcom, fucom, ftst:都是比较操作,然后设定对应的status register中condition code,ftst表示临时实数和0比较的结果