| 1 |
Ddoc |
|---|
| 2 |
|
|---|
| 3 |
$(SPEC_S $(TITLE), |
|---|
| 4 |
|
|---|
| 5 |
$(P Although D is designed to make it easy to port code between |
|---|
| 6 |
32 and 64 bit modes, being a systems programming language, |
|---|
| 7 |
dependencies can creep in. This guide points out what changes |
|---|
| 8 |
between the two. |
|---|
| 9 |
) |
|---|
| 10 |
|
|---|
| 11 |
$(SECTION2 Versions, |
|---|
| 12 |
$(P Not all code can be made portable between 32 and 64 bits, |
|---|
| 13 |
and must be versioned. The following works: |
|---|
| 14 |
) |
|---|
| 15 |
|
|---|
| 16 |
--- |
|---|
| 17 |
version (X86) |
|---|
| 18 |
... 32 bit code ... |
|---|
| 19 |
else version (X86_64) |
|---|
| 20 |
... 64 bit code ... |
|---|
| 21 |
else |
|---|
| 22 |
static assert("unsupported target") |
|---|
| 23 |
--- |
|---|
| 24 |
|
|---|
| 25 |
$(P It is best to write versioning in that manner to give a compile |
|---|
| 26 |
time error on a new target, rather than guessing in advance what, for example, |
|---|
| 27 |
a 64 bit ARM target might require. |
|---|
| 28 |
Experience shows that guesses about how an unfamiliar platform might work |
|---|
| 29 |
always get it wrong. |
|---|
| 30 |
Save those decisions for when one is actually working on a 64 bit ARM. |
|---|
| 31 |
) |
|---|
| 32 |
) |
|---|
| 33 |
|
|---|
| 34 |
$(SECTION2 Size Changes, |
|---|
| 35 |
|
|---|
| 36 |
$(P The size of pointers and references will increase from 4 |
|---|
| 37 |
to 8 bytes. The $(TT size_t) alias moves from $(TT uint) to |
|---|
| 38 |
$(TT ulong), and the $(TT ptrdiff_t) alias moves from $(TT int) |
|---|
| 39 |
to $(TT long). |
|---|
| 40 |
) |
|---|
| 41 |
|
|---|
| 42 |
$(P The sizes of compound types based on these will also increase. |
|---|
| 43 |
This includes dynamic arrays, associative arrays, delegates, |
|---|
| 44 |
and class references. |
|---|
| 45 |
) |
|---|
| 46 |
) |
|---|
| 47 |
|
|---|
| 48 |
$(SECTION2 Structs, |
|---|
| 49 |
|
|---|
| 50 |
$(P The size of the struct and the alignment of its fields |
|---|
| 51 |
will change, in order to match the C ABI of the equivalent |
|---|
| 52 |
C struct. |
|---|
| 53 |
) |
|---|
| 54 |
) |
|---|
| 55 |
|
|---|
| 56 |
$(SECTION2 Classes, |
|---|
| 57 |
|
|---|
| 58 |
$(P The size of the class and the alignment of its fields |
|---|
| 59 |
will change, in order to match the alignment most suitable |
|---|
| 60 |
for the 64 bit mode, and in order to accommodate the increased |
|---|
| 61 |
size of pointers and references. |
|---|
| 62 |
) |
|---|
| 63 |
) |
|---|
| 64 |
|
|---|
| 65 |
$(SECTION2 printf, |
|---|
| 66 |
|
|---|
| 67 |
$(P Since $(TT printf) is a C function, it follows C typing rules. |
|---|
| 68 |
This can have consequences for using them with D types. |
|---|
| 69 |
) |
|---|
| 70 |
|
|---|
| 71 |
$(TABLE1 |
|---|
| 72 |
$(TR <th rowspan=2>D Type</th> <th colspan=2>printf format</th>) |
|---|
| 73 |
$(TR $(TH 32 bit) $(TH 64 bit)) |
|---|
| 74 |
$(TR $(TD $(I T)*) $(TD %p) $(TD %p)) |
|---|
| 75 |
$(TR $(TD long) $(TD %lld) $(TD %d)) |
|---|
| 76 |
$(TR $(TD ulong) $(TD %llu) $(TD %u)) |
|---|
| 77 |
$(TR $(TD ptrdiff_t) $(TD %td) $(TD %td)) |
|---|
| 78 |
$(TR $(TD size_t) $(TD %zu) $(TD %zu)) |
|---|
| 79 |
) |
|---|
| 80 |
|
|---|
| 81 |
$(P For 32 bit code, it was common to use the $(TT %.*s) format |
|---|
| 82 |
to print strings. This relied on the 32 bit C ABI interpreting the |
|---|
| 83 |
components of a dynamic array as separate length and pointer arguments. |
|---|
| 84 |
64 bit parameter passing is different, and so the length and pointer |
|---|
| 85 |
should be done explicitly: |
|---|
| 86 |
) |
|---|
| 87 |
|
|---|
| 88 |
--- |
|---|
| 89 |
string s; |
|---|
| 90 |
... |
|---|
| 91 |
printf("s = '%.*s'\n", s); // 32 bit only |
|---|
| 92 |
printf("s = '%.*s'\n", s.length, s.ptr); // 32 and 64 bit |
|---|
| 93 |
--- |
|---|
| 94 |
) |
|---|
| 95 |
|
|---|
| 96 |
$(SECTION2 Inline Assembly, |
|---|
| 97 |
|
|---|
| 98 |
$(P Naturally, inline assembly for 32 bit code won't work for 64 bit code. |
|---|
| 99 |
The versioning statements to use are: |
|---|
| 100 |
) |
|---|
| 101 |
|
|---|
| 102 |
--- |
|---|
| 103 |
version (D_InlineAsm_X86) |
|---|
| 104 |
... 32 bit assembler ... |
|---|
| 105 |
version (D_InlineAsm_X86_64) |
|---|
| 106 |
... 64 bit assembler ... |
|---|
| 107 |
else |
|---|
| 108 |
static assert("unsupported target"); |
|---|
| 109 |
--- |
|---|
| 110 |
|
|---|
| 111 |
$(P The 64 bit inline assembler uses the syntax found in the Intel |
|---|
| 112 |
and AMD instruction set references. |
|---|
| 113 |
) |
|---|
| 114 |
) |
|---|
| 115 |
|
|---|
| 116 |
$(SECTION2 Variadic Arguments, |
|---|
| 117 |
|
|---|
| 118 |
$(P How variadic arguments work in 64 bits is radically different from |
|---|
| 119 |
32 bits. They are not a simple array on the stack. You will need to use |
|---|
| 120 |
the functions and templates in $(TT std.c.stdarg) to access them. |
|---|
| 121 |
) |
|---|
| 122 |
|
|---|
| 123 |
) |
|---|
| 124 |
|
|---|
| 125 |
) |
|---|
| 126 |
|
|---|
| 127 |
Macros: |
|---|
| 128 |
TITLE=Porting 32 Bit Code to 64 Bits |
|---|
| 129 |
WIKI=32To64 |
|---|