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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_BINUTILS_PREFIX_H
#define XM_BINUTILS_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#define XM_BINUTILS_FORMAT_COFF 1
#define XM_BINUTILS_FORMAT_ELF 2
#define XM_BINUTILS_FORMAT_MACHO 3
#define XM_BINUTILS_FORMAT_AR 4
#define XM_BINUTILS_FORMAT_PE 5
#define XM_BINUTILS_FORMAT_SHEBANG 6
#define XM_BINUTILS_FORMAT_APE 7
#define XM_BINUTILS_FORMAT_WASM 8
#define XM_BINUTILS_FORMAT_UNKNOWN 0
// COFF machine types (for format detection)
#define XM_BINUTILS_COFF_MACHINE_I386 0x014c
#define XM_BINUTILS_COFF_MACHINE_AMD64 0x8664
#define XM_BINUTILS_COFF_MACHINE_ARM 0x01c0
#define XM_BINUTILS_COFF_MACHINE_ARM64 0xaa64
// PE/DOS offsets/signatures (for format detection)
#define XM_BINUTILS_PE_DOS_STUB_MIN_SIZE (0x40)
#define XM_BINUTILS_PE_DOS_ELFANEW_OFFSET (0x3c)
#define XM_BINUTILS_PE_NT_SIGNATURE (0x00004550) // "PE\0\0" little endian
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
tb_int_t xm_binutils_format_detect(tb_stream_ref_t istream);
/* //////////////////////////////////////////////////////////////////////////////////////
* inline implementation
*/
/* read magic bytes from stream (preserves stream position)
*
* @param istream the input stream
* @param magic the buffer to store magic bytes (must be at least 4 bytes)
* @param size the number of bytes to read (typically 4)
*
* @return tb_true on success, tb_false on failure
*/
static __tb_inline__ tb_bool_t xm_binutils_read_magic(tb_stream_ref_t istream, tb_uint8_t *magic, tb_size_t size) {
tb_assert_and_check_return_val(istream && magic && size > 0, tb_false);
tb_hize_t saved_pos = tb_stream_offset(istream);
if (!tb_stream_seek(istream, 0)) {
return tb_false;
}
tb_bool_t ok = tb_false;
if (tb_stream_bread(istream, magic, size)) {
ok = tb_true;
}
tb_stream_seek(istream, saved_pos);
return ok;
}
/* copy data from input stream to output stream
*
* @param istream the input stream
* @param ostream the output stream
* @param size the size to copy
*
* @return tb_true on success, tb_false on failure
*/
static __tb_inline__ tb_bool_t xm_binutils_stream_copy(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_hize_t size) {
tb_assert_and_check_return_val(istream && ostream, tb_false);
if (size == 0) {
return tb_true;
}
tb_byte_t data[TB_STREAM_BLOCK_MAXN];
tb_hize_t writ = 0;
do {
tb_size_t need = (tb_size_t)tb_min(size - writ, (tb_hize_t)TB_STREAM_BLOCK_MAXN);
tb_check_break(need);
if (!tb_stream_bread(istream, data, need)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, data, need)) {
return tb_false;
}
writ += need;
tb_check_break(writ < size);
} while (1);
return tb_true;
}
/* sanitize symbol name (replace non-alphanumeric characters with underscores)
*
* @param name the symbol name
*/
static __tb_inline__ void xm_binutils_sanitize_symbol_name(tb_char_t* name) {
tb_assert_and_check_return(name);
for (tb_size_t i = 0; name[i]; i++) {
if (!tb_isalpha(name[i]) && !tb_isdigit(name[i]) && name[i] != '_') {
name[i] = '_';
}
}
}
/* read string from stream at specified offset
*
* @param istream the input stream
* @param offset the offset to read from
* @param name the buffer to store the string
* @param name_size the size of the buffer
*
* @return tb_true on success, tb_false on failure
*/
static __tb_inline__ tb_bool_t xm_binutils_read_string(tb_stream_ref_t istream, tb_hize_t offset, tb_char_t *name, tb_size_t name_size) {
tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false);
tb_hize_t saved_pos = tb_stream_offset(istream);
if (!tb_stream_seek(istream, offset)) {
return tb_false;
}
tb_size_t pos = 0;
tb_byte_t c;
while (pos < name_size - 1) {
if (!tb_stream_bread(istream, &c, 1)) {
tb_stream_seek(istream, saved_pos);
return tb_false;
}
if (c == 0) {
break;
}
name[pos++] = (tb_char_t)c;
}
name[pos] = '\0';
tb_stream_seek(istream, saved_pos);
return tb_true;
}
/* check if architecture is 64-bit
*
* @param arch the architecture string
* @return tb_true if 64-bit, tb_false otherwise
*/
static __tb_inline__ tb_bool_t xm_binutils_arch_is_64bit(tb_char_t const *arch) {
if (!arch) {
return tb_true;
}
// x86_64
if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) {
return tb_true;
}
// ARM64
else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0 ||
tb_strcmp(arch, "arm64-v8a") == 0) {
return tb_true;
}
// MIPS64
else if (tb_strncmp(arch, "mips64", 6) == 0) {
return tb_true;
}
// PowerPC64
else if (tb_strncmp(arch, "ppc64", 5) == 0 || tb_strncmp(arch, "powerpc64", 9) == 0) {
return tb_true;
}
// RISC-V 64
else if (tb_strncmp(arch, "riscv64", 7) == 0 ||
(tb_strncmp(arch, "riscv", 5) == 0 && tb_strstr(arch, "64"))) {
return tb_true;
}
// SPARC64
else if (tb_strncmp(arch, "sparc64", 7) == 0) {
return tb_true;
}
// s390x
else if (tb_strcmp(arch, "s390x") == 0) {
return tb_true;
}
// LoongArch64
else if (tb_strncmp(arch, "loongarch64", 11) == 0) {
return tb_true;
}
// WebAssembly 64
else if (tb_strcmp(arch, "wasm64") == 0) {
return tb_true;
}
// IA-64
else if (tb_strcmp(arch, "ia64") == 0 || tb_strcmp(arch, "itanium") == 0) {
return tb_true;
}
return tb_false;
}
#endif
|