エンディアン
レジスタ(AX)にメモリ設定時、AHに下位アドレスを、ALに上位アドレスを設定するシステムをリトルエンディアン、その逆をビッグエンディアンと言い、数値データのメモリ設定で、下位アドレスをデータの終了とするのをリトルエンディアン。上位アドレスをデータの終了とするのをビッグエンディアン。とう事です。X86はリトルエンディアンです。
ビッグエンディアンデータをリトルエンディアンシステムで取り扱ったサンプルです。
ext2_iget()でext2のスーパブロックデータからinodeの各種設定を行います。スーパブロックデータはリトルエンディアンで、inodeの各種設定はシステムエンディアン依存のle16_to_cpu()でリトルエンディアンをシステムがビッグエンディアンならbswap()で修正します。
ビッグエンディアンデータをリトルエンディアンシステムで取り扱ったサンプルです。
#include "stdio.h" #include "byteswap.h" void main() { char big_endian[] = {0x01, 0x02, 0x03, 0x04}; short int *a; long int *b; char *c; printf("short %d byte\n", sizeof(*a)); printf("long %d byte\n\n", sizeof(*b)); a = (short int *)big_endian; b = (long int *)big_endian; c = big_endian; printf("%02x%02x%02x%02x\n\n", *c, *(c + 1), *(c + 2), *(c + 3)); printf("%08x\n", *a); printf("%08x\n\n", *b); printf("%08x\n", bswap_16(*a)); printf("%08x\n", bswap_32(*b)); }
[root@localhost north]# ./endial short 2 byte long 4 byte 01020304 00000201 04030201 00000102 01020304システム外のデータ(ファイル/通信等)をやり取りする場合、そのデータのエンディアンとシステムのエンディアンに依存したデータ参照となります。
ext2_iget()でext2のスーパブロックデータからinodeの各種設定を行います。スーパブロックデータはリトルエンディアンで、inodeの各種設定はシステムエンディアン依存のle16_to_cpu()でリトルエンディアンをシステムがビッグエンディアンならbswap()で修正します。
#if BYTE_ORDER == LITTLE_ENDIAN #define le16_to_cpu(val) (val) #define le32_to_cpu(val) (val) #endif #if BYTE_ORDER == BIG_ENDIAN #define le16_to_cpu(val) bswap_16(val) #define le32_to_cpu(val) bswap_32(val) #endif struct ext2_inode { __le16 i_mode; /* File mode */ __le16 i_uid; /* Low 16 bits of Owner Uid */ __le32 i_size; /* Size in bytes */ __le32 i_atime; /* Access time */ __le32 i_ctime; /* Creation time */ __le32 i_mtime; /* Modification time */ __le32 i_dtime; /* Deletion Time */ __le16 i_gid; /* Low 16 bits of Group Id */ __le16 i_links_count; /* Links count */ __le32 i_blocks; /* Blocks count */ __le32 i_flags; /* File flags */ union { struct { __le32 l_i_reserved1; } linux1; struct { __le32 h_i_translator; } hurd1; struct { __le32 m_i_reserved1; } masix1; } osd1; /* OS dependent 1 */ __le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ __le32 i_generation; /* File version (for NFS) */ __le32 i_file_acl; /* File ACL */ __le32 i_dir_acl; /* Directory ACL */ __le32 i_faddr; /* Fragment address */ union { struct { __u8 l_i_frag; /* Fragment number */ __u8 l_i_fsize; /* Fragment size */ __u16 i_pad1; __le16 l_i_uid_high; /* these 2 fields */ __le16 l_i_gid_high; /* were reserved2[0] */ __u32 l_i_reserved2; } linux2; struct { __u8 h_i_frag; /* Fragment number */ __u8 h_i_fsize; /* Fragment size */ __le16 h_i_mode_high; __le16 h_i_uid_high; __le16 h_i_gid_high; __le32 h_i_author; } hurd2; struct { __u8 m_i_frag; /* Fragment number */ __u8 m_i_fsize; /* Fragment size */ __u16 m_pad1; __u32 m_i_reserved2[2]; } masix2; } osd2; /* OS dependent 2 */ }; struct inode *ext2_iget (struct super_block *sb, unsigned long ino) { struct ext2_inode_info *ei; struct buffer_head * bh; struct ext2_inode *raw_inode; struct inode *inode; long ret = -EIO; int n; inode = iget_locked(sb, ino); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) return inode; ei = EXT2_I(inode); ei->i_block_alloc_info = NULL; raw_inode = ext2_get_inode(inode->i_sb, ino, &bh); if (IS_ERR(raw_inode)) { ret = PTR_ERR(raw_inode); goto bad_inode; } inode->i_mode = le16_to_cpu(raw_inode->i_mode); inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); if (!(test_opt (inode->i_sb, NO_UID32))) { inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; } set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); inode->i_size = le32_to_cpu(raw_inode->i_size); inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime); inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime); inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime); inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0; ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) { /* this inode is deleted */ brelse (bh); ret = -ESTALE; goto bad_inode; } inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); ei->i_flags = le32_to_cpu(raw_inode->i_flags); ei->i_faddr = le32_to_cpu(raw_inode->i_faddr); ei->i_frag_no = raw_inode->i_frag; ei->i_frag_size = raw_inode->i_fsize; ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl); ei->i_dir_acl = 0; if (S_ISREG(inode->i_mode)) inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32; else ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); ei->i_dtime = 0; inode->i_generation = le32_to_cpu(raw_inode->i_generation); ei->i_state = 0; ei->i_block_group = (ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb); ei->i_dir_start_lookup = 0; for (n = 0; n < EXT2_N_BLOCKS; n++) ei->i_data[n] = raw_inode->i_block[n]; if (S_ISREG(inode->i_mode)) { inode->i_op = &ext2_file_inode_operations; if (ext2_use_xip(inode->i_sb)) { inode->i_mapping->a_ops = &ext2_aops_xip; inode->i_fop = &ext2_xip_file_operations; } else if (test_opt(inode->i_sb, NOBH)) { inode->i_mapping->a_ops = &ext2_nobh_aops; inode->i_fop = &ext2_file_operations; } else { inode->i_mapping->a_ops = &ext2_aops; inode->i_fop = &ext2_file_operations; } } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &ext2_dir_inode_operations; inode->i_fop = &ext2_dir_operations; if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_nobh_aops; else inode->i_mapping->a_ops = &ext2_aops; } else if (S_ISLNK(inode->i_mode)) { if (ext2_inode_is_fast_symlink(inode)) { inode->i_op = &ext2_fast_symlink_inode_operations; nd_terminate_link(ei->i_data, inode->i_size, sizeof(ei->i_data) - 1); } else { inode->i_op = &ext2_symlink_inode_operations; if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_nobh_aops; else inode->i_mapping->a_ops = &ext2_aops; } } else { inode->i_op = &ext2_special_inode_operations; if (raw_inode->i_block[0]) init_special_inode(inode, inode->i_mode, old_decode_dev(le32_to_cpu(raw_inode->i_block[0]))); else init_special_inode(inode, inode->i_mode, new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); } brelse (bh); ext2_set_inode_flags(inode); unlock_new_inode(inode); return inode; bad_inode: iget_failed(inode); return ERR_PTR(ret); }le16/le32/le64はshort/int/long、__attribute__((bitwise))のbitwiseはgccの機能でなく、sparceコマンドと称するパーサでle16_to_cpu()/le32_to_cpu()を介さないで参照されてないかをチェックするための属性のようです。
typedef __u16 __bitwise __le16; typedef __u32 __bitwise __le32; typedef __u64 __bitwise __le64; typedef unsigned short __u16; typedef unsigned int __u32; typedef unsigned long __u64; #ifdef __CHECK_ENDIAN__ #define __bitwise __bitwise__ #else #define __bitwise #endif #ifdef __CHECKER__ #define __bitwise__ __attribute__((bitwise)) #else #define __bitwise__ #endif