linux内核设计与实现--19章 可移植性

可移植的操作系统尽可能少的涉及与机器相关的代码,为了支持不同的体系结构,界面和功能在定义时尽最大可能的有普遍性和抽象性。一个一致性非常高而本身有比较简单的操作系统在支持新的体系结构时,可能只需修改很少量的代码,但是可能会存在与体系结构相关的功能无法使用的现象。Linux在可移植性方面使用了折中的路线,差不多所有的接口和核心代码都是独立于硬件结构的C语言代码,但对于性能要求严格的部分,内核的特性会根据不同的硬件体系进行调整。

可移植性的另一个关键问题就是数据类型,本书对于系统结构在可移植性方面分析的较少,相对更多的注意力放在了这里。

对于支持的每一种体系结构,Linux都要将<asm/types.h>中的BITS_PER_LONG定义为Clong类型的长度,也就是系统字长,下面是linux的系统字长对照表。


Table 19.1 Supported Linux Architectures

Architecture                       Description                          Word Size

alpha                                  Digital Alpha                        64 bits

arm                                     ARM and StrongARM         32 bits

avr                                      AVR                                         32 bits

blackfin                             Blackfin                                  32 bits

cris                                    CRIS                                       32 bits

frv                                       FR-V                                        32 bits

h8300                                H8/300                                   32 bits

ia64                                    IA-64                                       64 bits

m32r                                  M32xxx                                    32 bits

m68k                                  Motorola 68k                         32 bits

m68knommu                     m68k without MMU            32bits

mips                                  MIPS                                        32 and 64 bits

parisc HP                         PA-RISC                                  32 and 64bits

powerpc                           PowerPC                                  32 and 64 bits

s390                                    IBM S/390                              32 and 64 bits

Sh Hitachi SH 32 bits

Sparc SPARC 32 and 64 bits

xtensa Xtensa 32 bits


牢记下面的规则:

  • ANSI C标准规定,一个char的长度一定是1个字节;

  • 尽管没有规定int类型的长度是32bit,但是linux当前所有支持的体系结构中,它都是32位的;

  • short类型也类似,在当前所有支持的体系结构中,虽然没有明确规定,但都是16bit的;

  • 绝对不应该假定指针和long的长度,在Linux当前支持的体系结构中,他们可以在32bit64bit间变换;

  • 由于不同的体系结构的long长度不同,不应该假设sizeof(int) = sizeof(long );

  • 类似的,不要假设指针和int长度相等;


不透明类型隐藏着他的内部格式或结构,开发者利用typedef声明一个类型,把它叫做不透明类型。

处理不透明类型是的原则:

  • 不要假设类型的长度。这些类型在某些系统中可能是32bit,而在其他系统中又可能是64bit,并且,内核开发者可以任意修改这些类型的大小;

  • 不要将该类型转化回对应的C标准类型使用;

  • 编程时要保证在该类型实际存储空间和格式发生变化时代码不受影响;


char型的符号问题

大部分体系结构上,默认char是带符号的,它可以从-128127之间取值。但是也有例外,比如ARM结构,char就是不带符号的,他的取值范围是0-255.

因此,如果在自己的代码中使用了char型,要保证带符号和不带符号的情况下代码都没问题。如果能明确使用的哪一种,就直接声明它。


数据对齐

对齐是跟数据块在内存中的位置相关的话题,如果一个变量的内存地址正好是他的长度的整数倍,他就称作是自然对齐。

编译器会同过让所有的数据自然对齐来避免引发对齐问题。实际上,内核开发者在对齐上不用话费太多心思。

但了解一些也终归是好的嘛。

举个例子,将一个指向char型的指针当作指向unsignedlong型的指针用,会引起问题,因为此时会试图从一个并不能被48整除的内存地址上载入3264位的unsignedlong型数据。


非标准C数据类型按照下面原则对齐:

  • 对于数组,只要按照基本数据类型进行对齐就可以,随后的所有元素自然能够对齐;

  • 对于联合体,只要它包含的长度的最大数据类型能够对齐就可以;

  • 对于结构体,只要结构体每一个元素能够正确对齐就可以;


结构体的填补

为了保证每一个成员能够自然对齐,结构体要被填补。

例:

struct animal_struct {

     char dog;    /* 1 byte */

    unsigned long cat;    /* 4 bytes */

    unsigned short pig;    /* 2 bytes */

    char fox;    /* 1 byte */

};


在编译时为了满足各成员自然对齐,它在内存中不是按原样存放的。编译后:


struct animal_struct {

    char dog;     /*1 byte */

    u8 __pad0[3];    /*3 byte */

    unsigned long cat;    /*4 byte */

    unsigned short pig;    /*2 byte */

    char fox;    /*1 byte */

    u8 __pad1;    /*1 byte */

};


note:在大部分32bit系统上,对于任何这样一个结构体,sizeofanimal_struct)返回都是12.

当然可以通过重新排列结构体来避免填充:


struct animal_struct {

    unsigned long cat;    /*4 byte */

    unsigned short pig;    /*3 byte */

    char dog;    /*1 byte */

    char fox;    /*1 byte */

};


但是不是任何时候都可以对结构体进行调整,如果结构体是某个标准的一部分(比如USB),或是它是现有代码,它的成员次序就已经定死。


注意,ANSIC明确规定不允许编译器改变结构体内成员对象的次序—他是有程序员决定的。


字节顺序

如果最高有效位所在的字节放在低字节位置上,其他字节依次放在高字节位置上,那么该字节顺序称作高位优先(big-endian)。如果最低有效位所在的字节放在高字节位置上,其他字节依次存放在低字节位置上,那么就称做低位优先(little-endian)。


举个例子,如何判断是大端还是小端:


int x = 1;


if (*(char *)&x == 1)

    /* little endian */

else

    /* big endian */


对于Linux支持的每一种体系结构,相应的内核都会根据机器使用的字节顺序在他的<asm/byteorder.h>中定义__BIG_ENDIAN__LITTLE_ENDIAN中的一个。

这个头文件还从include/linux/byteorder/中包含了一组宏命令用于完成字节顺序之间的相互转换,命令包括:

u23 __cpu_to_be32(u32);    /*convertcpu’s byte order to big-endian */

u32 __cpu_to_le32(u32);     /*convertcpu’s byte order to little-endian */

u32 __be32_to_cpu(u32);     /*convertbig-endian to cpu’s byte order */

u32 __le32_to_cpus(u32);     /*convertlittle-endian to cpu’s byte order */


时间的计算

正确计量时间应该使用HZ,而不是jiffiesHZ定义在<asm/param.h>


最后一点就是关于页长度的问题,处理页管理内存时,绝对不要假设页的长度,不同体系结构的页长度见下表:

Table 19.4Architecture Page Size(s)

Architecture                                  PAGE_SHIFT                             PAGE_SIZE

alpha                                             13                                                  8KB

arm                                                12, 14, 15                                     4KB, 16KB, 32KB

avr                                                  12                                                   4KB

cris                                                 13                                                   8KB

blackfin                                          12                                                   4KB

frv                                                    14                                                   16KB

h8300                                             12                                                  4KB

                                                         12, 13, 14, 16                              4KB, 8KB, 16KB,64KB

m32r                                              12                                                    4KB

m68k                                              12, 13                                             4KB, 8KB

m68knommu                                12                                                   4KB

mips                                               12                                                   4KB

mn10300                                       12                                                   4KB

parisc                                             12                                                    4KB

powerpc                                        12                                                     4KB

s390                                              12                                                     4KB

sh                                                   12                                                     4KB

sparc                                             12, 13                                               4KB, 8KB

um                                                 12                                                      4KB

x86                                                 12                                                      4KB

xtensa                                            12                                                      4KB





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值