今天在看ld64的代码的时候, 看到了一个队平台属性的很好的封装, 所以模仿ld64写了一个。

平台属性

一般来说, 我们写的代码需要在多个平台运行, 注入: ppc, x86, x64等。 不同的平台可能又分为大段对齐和小段对齐。
在这里, 我们就只关注cpu架构和对齐方式。

不同平台差异

CPU架构 指针长度 数据存储方式
x86 32位 小端对齐
x64 64位 小端对齐
ppc 32位 大端对齐
ppc64 64位 大端对齐

C++隐藏平台细节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//
// ArchAbstractionPointer.h
// absrtactArchPointer
//
// Created by Axis on 2/23/16.
// Copyright © 2016 Axis. All rights reserved.
//

#ifndef ArchAbstractionPointer_h
#define ArchAbstractionPointer_h

#include <stdint.h>
#include <libkern/OSByteOrder.h>

#ifdef __OPTIMIZE__
#define INLINE __attribute__((always_inline))
#else
#define INLINE
#endif

class BigEndian
{
public:
//int16
static uint16_t get16(const uint16_t& from) INLINE { return OSReadBigInt(&from, 0);}
static void set16(uint16_t& info, uint16_t value) INLINE { OSWriteBigInt16(&info, 0, value);}

//int32
static uint32_t get32(const uint32_t& from) INLINE { return OSReadBigInt32(&from, 0); }
static void set32(uint32_t& info, uint32_t value) INLINE { OSWriteBigInt32(&info, 0, value); }

//int64
static uint64_t get64(const uint64_t& from) INLINE { return OSReadBigInt64(&from, 0); }
static void set64(uint64_t& info, uint64_t value) INLINE { OSWriteBigInt64(&info, 0, value); }

//bits
static uint32_t getBits(const uint32_t& from, uint8_t firstBit, uint8_t bitCount)
{

return getBitsRaw(get32(from), firstBit, bitCount);
}

static void setBits(uint32_t& info, uint32_t value, uint8_t firstBit, uint8_t bitCount)
{

uint32_t tmp = get32(info);
setBitsRaw(tmp, value, firstBit, bitCount);
}

//raw
static uint32_t getBitsRaw(const uint32_t& from, uint8_t firstBit, uint8_t bitCount) INLINE
{

return ((from>>(32-firstBit-bitCount)) & ((1<<bitCount)-1));
}

static void setBitsRaw(uint32_t& info, uint32_t value, uint8_t firstBit, uint8_t bitCount) INLINE
{

uint32_t tmp = info;
const uint32_t mask = ((1<<bitCount)-1);
tmp &= ~(mask<<(32-firstBit-bitCount)); //将firstBit~ bitCount的字段清零
tmp |= ((value&mask)<<(32-firstBit-bitCount));
info = tmp;
}

enum { little_endian = 0 };
};

class LittleEndian
{
public:
//16 bits
static uint16_t get16(const uint16_t& from) INLINE {return OSReadLittleInt16(&from, 0);}
static void set16(uint16_t& info, uint16_t value) INLINE {OSWriteLittleInt16(&info, 0, value);}

static uint32_t get32(const uint32_t& from) INLINE {return OSReadLittleInt32(&from, 0);}
static void set32(uint32_t& info, uint32_t value) INLINE { OSWriteLittleInt32(&info, 0, value); }

static uint64_t get64(const uint64_t& from) INLINE {return OSReadLittleInt64(&from, 0);}
static void set64(uint64_t& info, uint64_t value) INLINE { OSWriteLittleInt64(&info, 0, value); }

static uint32_t getBitRaw(const uint32_t& from, uint8_t firstBit, uint8_t bitCount) INLINE
{

return (from>>firstBit) & ((1<<bitCount)-1);
}

static void setBitRaw(uint32_t& from, uint32_t value, uint8_t firstBit, uint8_t bitCount)
{

uint32_t tmp = from;
const uint32_t mask = (1<<bitCount)-1; //set mask
tmp &= ~(mask << firstBit); //set zero
tmp |= (value&mask) << firstBit;
from = tmp;
}

enum { little_endian = 1 };
};

template <typename _E>
class Pointer32
{
public:
typedef uint32_t uint_t;
typedef int32_t sint_t;
typedef _E E;

static uint64_t getP(const uint_t& from) INLINE { return _E::get32(from); }
static void setP(uint_t& from, uint64_t value) INLINE { _E::set32(from, value); }
};

template <typename _E>
class Pointer64
{
public:
typedef uint64_t uint_t;
typedef int64_t sint_t;
typedef _E E;

static uint64_t getP(const uint_t& from) INLINE { return _E::get64(from); }
static uint64_t setP(uint_t& from, uint64_t value) INLINE { return _E::set64(from, value); }
};

#endif /* ArchAbstractionPointer_h */

调用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
template <typename P>
struct test_class {};

template<> struct test_class<Pointer32<BigEndian>> { const char* type = "32 pointer under big endian"; };
template<> struct test_class<Pointer32<LittleEndian>> {const char* type = "32 pointer under little endian"; };
template<> struct test_class<Pointer64<BigEndian>> { const char* type = "64 pointer under big endian"; };
template<> struct test_class<Pointer64<LittleEndian>> { const char* type = "64 pointer under little endian"; };

struct ppc
{
typedef Pointer32<BigEndian> P;
};

struct ppc64
{
typedef Pointer64<BigEndian> P;
};

struct x86
{
typedef Pointer32<LittleEndian> P;
};

struct x64
{
typedef Pointer64<LittleEndian> P;
};

template<typename T>
struct test_trail
{
private:
typedef typename T::P P;
typedef typename T::P::E E;
typedef typename T::P::uint_t puint_t;
};

int main(int argc, const char * argv[])
{

test_class<x64::P> test;
std::cout << test.type << std::endl;

test_class<ppc::P> test2;
std::cout << test2.type << std::endl;
}

Happy Hacking!
Axis