summaryrefslogtreecommitdiff
path: root/core/src/xmake/binutils/prefix.h
blob: 60842495883a90361d0a12b9ec7041776bf96e35 (plain)
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