Coverage Report

Created: 2026-02-26 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/upx/src/linker.cpp
Line
Count
Source
1
/* linker.cpp --
2
3
   This file is part of the UPX executable compressor.
4
5
   Copyright (C) Markus Franz Xaver Johannes Oberhumer
6
   Copyright (C) Laszlo Molnar
7
   All Rights Reserved.
8
9
   UPX and the UCL library are free software; you can redistribute them
10
   and/or modify them under the terms of the GNU General Public License as
11
   published by the Free Software Foundation; either version 2 of
12
   the License, or (at your option) any later version.
13
14
   This program is distributed in the hope that it will be useful,
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
19
   You should have received a copy of the GNU General Public License
20
   along with this program; see the file COPYING.
21
   If not, write to the Free Software Foundation, Inc.,
22
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24
   Markus F.X.J. Oberhumer              Laszlo Molnar
25
   <markus@oberhumer.com>               <ezerotven+github@gmail.com>
26
 */
27
28
#include "conf.h"
29
#define WANT_EHDR_ENUM 1
30
#include "p_elf_enum.h"
31
#include "linker.h"
32
33
0
static inline unsigned hex(uchar c) noexcept { return (c & 0xf) + (c > '9' ? 9 : 0); }
34
35
0
static bool grow_capacity(unsigned size, unsigned *capacity) noexcept {
36
0
    if (size < *capacity)
37
0
        return false;
38
0
    if (*capacity == 0)
39
0
        *capacity = 16;
40
0
    while (size >= *capacity)
41
0
        *capacity *= 2;
42
0
    return true;
43
0
}
44
45
template <class T>
46
0
static noinline T **realloc_array(T **array, size_t capacity) may_throw {
47
0
    assert_noexcept(capacity > 0);
48
    // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
49
0
    void *p = ::realloc(array, mem_size(sizeof(T *), capacity));
50
0
    assert_noexcept(p != nullptr);
51
0
    return static_cast<T **>(p);
52
0
}
Unexecuted instantiation: linker.cpp:ElfLinker::Section** realloc_array<ElfLinker::Section>(ElfLinker::Section**, unsigned long)
Unexecuted instantiation: linker.cpp:ElfLinker::Symbol** realloc_array<ElfLinker::Symbol>(ElfLinker::Symbol**, unsigned long)
Unexecuted instantiation: linker.cpp:ElfLinker::Relocation** realloc_array<ElfLinker::Relocation>(ElfLinker::Relocation**, unsigned long)
53
54
template <class T>
55
0
static noinline void free_array(T **array, size_t count) noexcept {
56
0
    for (size_t i = 0; i < count; i++) {
57
0
        T *item = upx::atomic_exchange(&array[i], (T *) nullptr);
58
0
        delete item;
59
0
    }
60
0
    ::free(array); // NOLINT(bugprone-multi-level-implicit-pointer-conversion)
61
0
}
Unexecuted instantiation: linker.cpp:void free_array<ElfLinker::Section>(ElfLinker::Section**, unsigned long)
Unexecuted instantiation: linker.cpp:void free_array<ElfLinker::Symbol>(ElfLinker::Symbol**, unsigned long)
Unexecuted instantiation: linker.cpp:void free_array<ElfLinker::Relocation>(ElfLinker::Relocation**, unsigned long)
62
63
/*************************************************************************
64
// Section
65
**************************************************************************/
66
67
ElfLinker::Section::Section(const char *n, const void *i, unsigned s, unsigned a)
68
0
    : name(nullptr), output(nullptr), size(s), offset(0), p2align(a), next(nullptr) {
69
0
    name = ::strdup(n);
70
0
    assert_noexcept(name != nullptr);
71
0
    input = ::malloc(s + 1);
72
0
    assert_noexcept(input != nullptr);
73
0
    if (s != 0) {
74
0
        assert_noexcept(i != nullptr);
75
0
        memcpy(input, i, s);
76
0
    }
77
0
    ((char *) input)[s] = 0;
78
0
}
79
80
0
ElfLinker::Section::~Section() noexcept {
81
0
    ::free(name);
82
0
    ::free(input);
83
0
}
84
85
/*************************************************************************
86
// Symbol
87
**************************************************************************/
88
89
ElfLinker::Symbol::Symbol(const char *n, Section *s, upx_uint64_t o)
90
0
    : name(nullptr), section(s), offset(o) {
91
0
    name = ::strdup(n);
92
0
    assert_noexcept(name != nullptr);
93
0
    assert_noexcept(section != nullptr);
94
0
}
95
96
0
ElfLinker::Symbol::~Symbol() noexcept { ::free(name); }
97
98
/*************************************************************************
99
// Relocation
100
**************************************************************************/
101
102
ElfLinker::Relocation::Relocation(const Section *s, unsigned o, const char *t, const Symbol *v,
103
                                  upx_uint64_t a)
104
0
    : section(s), offset(o), type(t), value(v), add(a) {
105
0
    assert_noexcept(section != nullptr);
106
0
}
107
108
/*************************************************************************
109
// ElfLinker
110
**************************************************************************/
111
112
0
ElfLinker::ElfLinker(const N_BELE_RTP::AbstractPolicy *b) noexcept : bele(b) {}
113
114
0
ElfLinker::~ElfLinker() noexcept {
115
0
    delete[] input;
116
0
    delete[] output;
117
0
    free_array(sections, nsections);
118
0
    free_array(symbols, nsymbols);
119
0
    free_array(relocations, nrelocations);
120
0
}
121
122
0
void ElfLinker::init(unsigned arch, const void *pdata_v, int plen, unsigned pxtra) {
123
0
    const byte *pdata = (const byte *) pdata_v;
124
0
    this->e_machine = arch;
125
0
    if (plen >= 16 && memcmp(pdata, "UPX#", 4) == 0) {
126
        // decompress pre-compressed stub-loader
127
0
        int method;
128
0
        unsigned u_len, c_len;
129
0
        if (pdata[4]) {
130
0
            method = pdata[4];
131
0
            u_len = get_le16(pdata + 5);
132
0
            c_len = get_le16(pdata + 7);
133
0
            pdata += 9;
134
0
            assert(9 + c_len == (unsigned) plen);
135
0
        } else {
136
0
            method = pdata[5];
137
0
            u_len = get_le32(pdata + 6);
138
0
            c_len = get_le32(pdata + 10);
139
0
            pdata += 14;
140
0
            assert(14 + c_len == (unsigned) plen);
141
0
        }
142
0
        assert((unsigned) plen < u_len);
143
0
        inputlen = u_len;
144
0
        input = New(byte, inputlen + 1);
145
0
        unsigned new_len = u_len;
146
0
        int r = upx_decompress(pdata, c_len, input, &new_len, method, nullptr);
147
0
        if (r == UPX_E_OUT_OF_MEMORY)
148
0
            throwOutOfMemoryException();
149
0
        if (r != UPX_E_OK || new_len != u_len)
150
0
            throwBadLoader();
151
0
    } else {
152
0
        inputlen = plen;
153
0
        input = New(byte, inputlen + 1);
154
0
        if (inputlen)
155
0
            memcpy(input, pdata, inputlen);
156
0
    }
157
0
    input[inputlen] = 0; // NUL terminate
158
159
0
    output_capacity = (inputlen ? (inputlen + pxtra) : 0x4000);
160
0
    assert(output_capacity < (1 << 16)); // LE16 l_info.l_size
161
0
    output = New(byte, output_capacity);
162
0
    outputlen = 0;
163
0
    NO_printf("\nElfLinker::init %d @%p\n", output_capacity, output);
164
165
    // FIXME: bad compare when either symbols or relocs are absent
166
0
    if ((int) strlen("Sections:\n"
167
0
                     "SYMBOL TABLE:\n"
168
0
                     "RELOCATION RECORDS FOR ") < inputlen) {
169
0
        char const *const eof = (char const *) &input[inputlen];
170
0
        int pos = find(input, inputlen, "Sections:\n", 10);
171
0
        assert(pos != -1);
172
0
        char *const psections = (char *) input + pos;
173
174
0
        char *const psymbols = strstr(psections, "SYMBOL TABLE:\n");
175
        // assert(psymbols != nullptr);
176
177
0
        char *const prelocs = strstr((psymbols ? psymbols : psections), "RELOCATION RECORDS FOR ");
178
        // assert(prelocs != nullptr);
179
180
0
        preprocessSections(psections, (psymbols ? psymbols : (prelocs ? prelocs : eof)));
181
0
        if (psymbols)
182
0
            preprocessSymbols(psymbols, (prelocs ? prelocs : eof));
183
0
        if (prelocs)
184
0
            preprocessRelocations(prelocs, eof);
185
0
        addLoader("*UND*");
186
0
    }
187
0
}
188
189
0
void ElfLinker::preprocessSections(char *start, char const *end) {
190
0
    assert_noexcept(nsections == 0);
191
0
    char *nextl;
192
0
    for (; start < end; start = 1 + nextl) {
193
0
        nextl = strchr(start, '\n');
194
0
        assert(nextl != nullptr);
195
0
        *nextl = '\0'; // a record is a line
196
197
0
        unsigned offset, size, align;
198
0
        char name[1024];
199
200
0
        if (sscanf(start, "%*d %1023s %x %*x %*x %x 2**%d", name, &size, &offset, &align) == 4) {
201
0
            char *n = strstr(start, name);
202
0
            n[strlen(name)] = 0;
203
0
            addSection(n, input + offset, size, align);
204
0
            NO_printf("section %s preprocessed\n", n);
205
0
        }
206
0
    }
207
0
    addSection("*ABS*", nullptr, 0, 0);
208
0
    addSection("*UND*", nullptr, 0, 0);
209
0
}
210
211
0
void ElfLinker::preprocessSymbols(char *start, char const *end) {
212
0
    assert_noexcept(nsymbols <= 1);
213
0
    char *nextl;
214
0
    for (; start < end; start = 1 + nextl) {
215
0
        nextl = strchr(start, '\n');
216
0
        assert(nextl != nullptr);
217
0
        *nextl = '\0'; // a record is a line
218
219
0
        unsigned value, offset;
220
0
        char section[1024];
221
0
        char symbol[1024];
222
223
0
        if (sscanf(start, "%x g *ABS* %x %1023s", &value, &offset, symbol) == 3) {
224
0
            char *s = strstr(start, symbol);
225
0
            s[strlen(symbol)] = 0;
226
0
            addSymbol(s, "*ABS*", value);
227
0
            assert(offset == 0);
228
0
        }
229
#if 0
230
        else if (sscanf(start, "%x%*8c %1023s %*x %1023s", &offset, section, symbol) == 3)
231
#else
232
        // work around broken scanf() implementations
233
        // https://bugs.winehq.org/show_bug.cgi?id=10401 (fixed in Wine 0.9.58)
234
0
        else if (sscanf(start, "%x%*c%*c%*c%*c%*c%*c%*c%*c %1023s %*x %1023s", &offset, section,
235
0
                        symbol) == 3)
236
0
#endif
237
0
        {
238
0
            char *s = strstr(start, symbol);
239
0
            s[strlen(symbol)] = 0;
240
0
            if (strcmp(section, "*UND*") == 0)
241
0
                offset = 0xdeaddead;
242
0
            assert(strcmp(section, "*ABS*") != 0);
243
0
            addSymbol(s, section, offset);
244
0
        }
245
0
    }
246
0
}
247
248
0
void ElfLinker::preprocessRelocations(char *start, char const *end) {
249
0
    assert_noexcept(nrelocations == 0);
250
0
    Section *section = nullptr;
251
0
    char *nextl;
252
0
    for (; start < end; start = 1 + nextl) {
253
0
        nextl = strchr(start, '\n');
254
0
        assert(nextl != nullptr);
255
0
        *nextl = '\0'; // a record is a line
256
257
0
        {
258
0
            char sect[1024];
259
0
            if (sscanf(start, "RELOCATION RECORDS FOR [%[^]]", sect) == 1)
260
0
                section = findSection(sect);
261
0
        }
262
263
0
        unsigned offset;
264
0
        char type[100];
265
0
        char symbol[1024];
266
267
0
        if (sscanf(start, "%x %99s %1023s", &offset, type, symbol) == 3) {
268
0
            char *t = strstr(start, type);
269
0
            t[strlen(type)] = 0;
270
271
0
            upx_uint64_t add = 0;
272
0
            char *p = strstr(symbol, "+0x");
273
0
            if (p == nullptr)
274
0
                p = strstr(symbol, "-0x");
275
0
            if (p) {
276
0
                char sign = *p;
277
0
                *p = 0; // terminate the symbol name
278
0
                p += 3;
279
0
                assert(strlen(p) == 8 || strlen(p) == 16);
280
#if (ACC_CC_MSC && (_MSC_VER < 1800))
281
                unsigned a = 0, b = 0;
282
                if (sscanf(p, "%08x%08x", &a, &b) == 2)
283
                    add = ((upx_uint64_t) a << 32) | b;
284
                else
285
                    add = a;
286
#else
287
0
                char *endptr = nullptr;
288
0
                add = strtoull(p, &endptr, 16);
289
0
                assert(endptr && *endptr == '\0');
290
0
#endif
291
0
                if (sign == '-')
292
0
                    add = 0 - add;
293
0
            }
294
295
0
            if (section) {
296
0
                addRelocation(section->name, offset, t, symbol, add);
297
0
                NO_printf("relocation %s %s %x %llu preprocessed\n", section->name, symbol, offset,
298
0
                          (unsigned long long) add);
299
0
            }
300
0
        }
301
0
    }
302
0
}
303
304
0
ElfLinker::Section *ElfLinker::findSection(const char *name, bool fatal) const {
305
0
    for (unsigned ic = 0; ic < nsections; ic++)
306
0
        if (strcmp(sections[ic]->name, name) == 0)
307
0
            return sections[ic];
308
0
    if (fatal)
309
0
        throwInternalError("unknown section %s\n", name);
310
0
    return nullptr;
311
0
}
312
313
0
ElfLinker::Symbol *ElfLinker::findSymbol(const char *name, bool fatal) const {
314
0
    for (unsigned ic = 0; ic < nsymbols; ic++)
315
0
        if (strcmp(symbols[ic]->name, name) == 0)
316
0
            return symbols[ic];
317
0
    if (fatal)
318
0
        throwInternalError("unknown symbol %s\n", name);
319
0
    return nullptr;
320
0
}
321
322
ElfLinker::Section *ElfLinker::addSection(const char *sname, const void *sdata, int slen,
323
0
                                          unsigned p2align) {
324
0
    NO_printf("addSection: %s len=%d align=%d\n", sname, slen, p2align);
325
0
    if (!sdata && (!strcmp("ABS*", sname) || !strcmp("UND*", sname)))
326
0
        return nullptr;
327
0
    assert(sname && sname[0]);
328
0
    assert(sname[strlen(sname) - 1] != ':');
329
0
    assert(findSection(sname, false) == nullptr);
330
0
    if (grow_capacity(nsections, &nsections_capacity))
331
0
        sections = realloc_array(sections, nsections_capacity);
332
0
    Section *sec = new Section(sname, sdata, slen, p2align);
333
0
    sec->sort_id = nsections;
334
0
    sections[nsections++] = sec;
335
0
    if ('*' == sname[0]) {
336
0
        if (!strcmp("*ABS*", sname)) {
337
0
            addSymbol("*ABS*", "*ABS*", 0);
338
0
        }
339
0
    }
340
0
    return sec;
341
0
}
342
343
ElfLinker::Symbol *ElfLinker::addSymbol(const char *name, const char *section,
344
0
                                        upx_uint64_t offset) {
345
0
    NO_printf("addSymbol: %s %s 0x%llx\n", name, section, offset);
346
0
    assert(name && name[0]);
347
0
    assert(name[strlen(name) - 1] != ':');
348
0
    assert(findSymbol(name, false) == nullptr);
349
0
    if (grow_capacity(nsymbols, &nsymbols_capacity))
350
0
        symbols = realloc_array(symbols, nsymbols_capacity);
351
0
    Symbol *sym = new Symbol(name, findSection(section), offset);
352
0
    symbols[nsymbols++] = sym;
353
0
    return sym;
354
0
}
355
356
ElfLinker::Relocation *ElfLinker::addRelocation(const char *section, unsigned off, const char *type,
357
0
                                                const char *symbol, upx_uint64_t add) {
358
0
    if (EM_RISCV == this->e_machine) {
359
0
        if ((symbol && '.' == symbol[0])        // compiler-generated; or 0f, 0b (etc.)
360
0
            && (!strcmp(type, "R_RISCV_BRANCH") // known types
361
0
                || !strcmp(type, "R_RISCV_RVC_BRANCH") || !strcmp(type, "R_RISCV_JAL") ||
362
0
                !strcmp(type, "R_RISCV_JUMP") || !strcmp(type, "R_RISCV_RVC_JUMP"))) {
363
0
            return nullptr; // ASSUME already relocated: source and target in same section
364
0
        }
365
0
    }
366
0
    if (grow_capacity(nrelocations, &nrelocations_capacity))
367
0
        relocations = realloc_array(relocations, nrelocations_capacity);
368
0
    NO_printf("addRelocation section=(%s +%#x)  symbol=(%s +%#x)\n", section, off, symbol,
369
0
              (unsigned) add);
370
0
    Relocation *rel = new Relocation(findSection(section), off, type, findSymbol(symbol), add);
371
0
    relocations[nrelocations++] = rel;
372
0
    return rel;
373
0
}
374
375
#if 0
376
void ElfLinker::setLoaderAlignOffset(int phase) {
377
    // assert(phase & 0);
378
    NO_printf("\nFIXME: ElfLinker::setLoaderAlignOffset %d\n", phase);
379
}
380
#endif
381
382
0
int ElfLinker::addLoader(const char *sname) {
383
0
    assert(sname != nullptr);
384
0
    if (!sname[0])
385
0
        return outputlen;
386
387
0
    char *begin = ::strdup(sname);
388
0
    assert_noexcept(begin != nullptr);
389
0
    const auto begin_deleter = upx::MallocDeleter(&begin, 1); // don't leak memory
390
0
    char *end = begin + strlen(begin);
391
0
    for (char *sect = begin; sect < end;) {
392
0
        for (char *tokend = sect; *tokend; tokend++)
393
0
            if (*tokend == ' ' || *tokend == ',') {
394
0
                *tokend = 0;
395
0
                break;
396
0
            }
397
398
0
        if (sect[0] == '+') { // alignment
399
0
            assert(tail);
400
0
            unsigned l = hex(sect[2]) - tail->offset - tail->size;
401
0
            unsigned m = hex(sect[1]);
402
0
            if (m) {
403
0
                l %= hex(sect[1]);
404
0
            }
405
0
            if (l) {
406
0
                if (sect[3] == 'D')
407
0
                    alignData(l);
408
0
                else
409
0
                    alignCode(l);
410
0
                tail->size += l;
411
0
            }
412
0
        } else {
413
0
            Section *section = findSection(sect);
414
0
            if (section->p2align) {
415
0
                assert(tail);
416
0
                assert(tail != section);
417
                // .p2align must be < 32
418
0
                const unsigned v = ~0u << section->p2align;
419
0
                if (const unsigned l = ~v & (0u - (unsigned) (tail->offset + tail->size))) {
420
0
                    alignCode(l);
421
0
                    tail->size += l;
422
0
                }
423
0
            }
424
            // Section->output is not relocatable, and C++ has no realloc() anyway.
425
0
            assert((section->size + outputlen) <= output_capacity);
426
0
            memcpy(output + outputlen, section->input, section->size);
427
0
            section->output = output + outputlen; // FIXME: INVALIDATED by realloc()
428
0
            NO_printf("section added: 0x%04x %3d %s\n", outputlen, section->size, section->name);
429
0
            outputlen += section->size;
430
431
0
            if (head) {
432
0
                tail->next = section;
433
0
                section->offset = tail->offset + tail->size;
434
0
            } else
435
0
                head = section;
436
0
            tail = section;
437
0
        }
438
0
        sect += strlen(sect) + 1;
439
0
    }
440
0
    return outputlen;
441
0
}
442
443
0
void ElfLinker::addLoader(const char *s, va_list ap) {
444
0
    while (s != nullptr) {
445
0
        addLoader(s);
446
0
        s = va_arg(ap, const char *);
447
0
    }
448
0
}
449
450
0
void ElfLinker::addLoaderVA(const char *s, ...) {
451
0
    va_list ap;
452
0
    va_start(ap, s);
453
0
    addLoader(s, ap);
454
0
    va_end(ap);
455
0
}
456
457
0
int ElfLinker::getSection(const char *sname, int *slen) const {
458
0
    const Section *section = findSection(sname);
459
0
    if (slen)
460
0
        *slen = section->size;
461
0
    return (int) (section->output - output);
462
0
}
463
464
0
int ElfLinker::getSectionSize(const char *sname) const {
465
0
    const Section *section = findSection(sname);
466
0
    return section->size;
467
0
}
468
469
0
byte *ElfLinker::getLoader(int *llen) const {
470
0
    if (llen)
471
0
        *llen = outputlen;
472
0
    return output;
473
0
}
474
475
0
void ElfLinker::relocate() {
476
0
    assert(!reloc_done);
477
0
    reloc_done = true;
478
0
    for (unsigned ic = 0; ic < nrelocations; ic++) {
479
0
        const Relocation *rel = relocations[ic];
480
0
        upx_uint64_t value = 0;
481
482
0
        if (rel->section->output == nullptr)
483
0
            continue;
484
0
        if (strcmp(rel->value->section->name, "*ABS*") == 0) {
485
0
            value = rel->value->offset;
486
0
        } else if (strcmp(rel->value->section->name, "*UND*") == 0 &&
487
0
                   rel->value->offset == 0xdeaddead)
488
0
            throwInternalError("undefined symbol '%s' referenced\n", rel->value->name);
489
0
        else if (rel->value->section->output == nullptr)
490
0
            throwInternalError("cannot apply reloc '%s:%x' without section '%s'\n",
491
0
                               rel->section->name, rel->offset, rel->value->section->name);
492
0
        else {
493
0
            value = rel->value->section->offset + rel->value->offset + rel->add;
494
0
        }
495
0
        byte *location = rel->section->output + rel->offset;
496
0
        NO_printf("%-28s %-28s %-10s %#16llx %#16llx\n", rel->section->name, rel->value->name,
497
0
                  rel->type, (long long) value,
498
0
                  (long long) value - rel->section->offset - rel->offset);
499
0
        NO_printf("  %llx %d %llx %d %llx :%d\n", (long long) value,
500
0
                  (int) rel->value->section->offset, rel->value->offset, rel->offset,
501
0
                  (long long) rel->add, *location);
502
0
        relocate1(rel, location, value, rel->type);
503
0
    }
504
0
}
505
506
0
void ElfLinker::defineSymbol(const char *name, upx_uint64_t value) {
507
0
    Symbol *symbol = findSymbol(name);
508
0
    if (strcmp(symbol->section->name, "*ABS*") == 0)
509
0
        throwInternalError("defineSymbol: symbol '%s' is *ABS*\n", name);
510
0
    else if (strcmp(symbol->section->name, "*UND*") == 0) // for undefined symbols
511
0
        symbol->offset = value;
512
0
    else if (strcmp(symbol->section->name, name) == 0) // for sections
513
0
    {
514
0
        for (Section *section = symbol->section; section; section = section->next) {
515
0
            assert(section->offset < value);
516
0
            section->offset = value;
517
0
            value += section->size;
518
0
        }
519
0
    } else
520
0
        throwInternalError("defineSymbol: symbol '%s' already defined\n", name);
521
0
}
522
523
// debugging support
524
0
void ElfLinker::dumpSymbol(const Symbol *symbol, unsigned flags, FILE *fp) const {
525
0
    if ((flags & 1) && symbol->section->output == nullptr)
526
0
        return;
527
0
    char d0[16 + 1], d1[16 + 1];
528
0
    upx_safe_snprintf(d0, sizeof(d0), "%016llx", (upx_uint64_t) symbol->offset);
529
0
    upx_safe_snprintf(d1, sizeof(d1), "%016llx", (upx_uint64_t) symbol->section->offset);
530
0
    fprintf(fp, "%-28s 0x%-16s | %-28s 0x%-16s\n", symbol->name, d0, symbol->section->name, d1);
531
0
}
532
0
void ElfLinker::dumpSymbols(unsigned flags, FILE *fp) const {
533
0
    if (fp == nullptr)
534
0
        fp = stdout;
535
0
    if ((flags & 2) == 0) {
536
        // default: dump symbols in used section order
537
0
        for (const Section *section = head; section; section = section->next) {
538
0
            char d1[16 + 1];
539
0
            upx_safe_snprintf(d1, sizeof(d1), "%016llx", (upx_uint64_t) section->offset);
540
0
            fprintf(fp, "%-42s%-28s 0x%-16s\n", "", section->name, d1);
541
0
            for (unsigned ic = 0; ic < nsymbols; ic++) {
542
0
                const Symbol *symbol = symbols[ic];
543
0
                if (symbol->section == section && strcmp(symbol->name, section->name) != 0)
544
0
                    dumpSymbol(symbol, flags, fp);
545
0
            }
546
0
        }
547
0
    } else {
548
        // dump all symbols
549
0
        for (unsigned ic = 0; ic < nsymbols; ic++)
550
0
            dumpSymbol(symbols[ic], flags, fp);
551
0
    }
552
0
}
553
554
0
upx_uint64_t ElfLinker::getSymbolOffset(const char *name) const {
555
0
    const Symbol *symbol = findSymbol(name);
556
0
    if (symbol->section->output == nullptr)
557
0
        return 0xdeaddead;
558
0
    return symbol->section->offset + symbol->offset;
559
0
}
560
561
0
void ElfLinker::alignWithByte(unsigned len, byte b) {
562
0
    memset(output + outputlen, b, len);
563
0
    outputlen += len;
564
0
}
565
566
0
void ElfLinker::relocate1(const Relocation *rel, byte *, upx_uint64_t, const char *) {
567
0
    throwInternalError("unknown relocation type '%s\n'", rel->type);
568
0
}
569
570
/*************************************************************************
571
// ElfLinker arch subclasses
572
// FIXME: add more displacement overflow checks
573
// FIXME: add support for our special "ignore_reloc_overflow" section
574
**************************************************************************/
575
576
#if 0 // FIXME
577
static void check8(const Relocation *rel, const byte *location, int v, int d) {
578
    if (v < -128 || v > 127)
579
        throwInternalError("value out of range (%d) in reloc %s:%x\n", v, rel->section->name,
580
                           rel->offset);
581
    if (d < -128 || d > 127)
582
        throwInternalError("displacement target out of range (%d) in reloc %s:%x\n", v,
583
                           rel->section->name, rel->offset);
584
}
585
#endif
586
587
void ElfLinkerAMD64::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
588
0
                               const char *type) {
589
0
    if (strncmp(type, "R_X86_64_", 9))
590
0
        return super::relocate1(rel, location, value, type);
591
0
    type += 9;
592
593
0
    bool range_check = false;
594
0
    if (strncmp(type, "PC", 2) == 0) {
595
0
        type += 2;
596
0
        value -= rel->section->offset + rel->offset;
597
0
        range_check = true;
598
0
    } else if (strncmp(type, "PLT", 3) == 0) {
599
0
        type += 3;
600
0
        value -= rel->section->offset + rel->offset;
601
0
        range_check = true;
602
0
    }
603
604
0
    if (strcmp(type, "8") == 0) {
605
0
        int displ = (upx_int8_t) *location + (int) value;
606
0
        if (range_check && (displ < -128 || displ > 127))
607
0
            throwInternalError("target out of range (%d) in reloc %s:%x\n", displ,
608
0
                               rel->section->name, rel->offset);
609
0
        *location += value;
610
0
    } else if (strcmp(type, "16") == 0)
611
0
        set_le16(location, get_le16(location) + value);
612
0
    else if (strncmp(type, "32", 2) == 0) // for "32" and "32S"
613
0
        set_le32(location, get_le32(location) + value);
614
0
    else if (strcmp(type, "64") == 0)
615
0
        set_le64(location, get_le64(location) + value);
616
0
    else
617
0
        super::relocate1(rel, location, value, type);
618
0
}
619
620
void ElfLinkerArmBE::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
621
0
                               const char *type) {
622
0
    if (!strcmp(type, "R_ARM_PC24") || !strcmp(type, "R_ARM_CALL") ||
623
0
        !strcmp(type, "R_ARM_JUMP24")) {
624
0
        value -= rel->section->offset + rel->offset;
625
0
        set_be24(1 + location, get_be24(1 + location) + value / 4);
626
0
    } else if (strcmp(type, "R_ARM_ABS32") == 0) {
627
0
        set_be32(location, get_be32(location) + value);
628
0
    } else if (strcmp(type, "R_ARM_THM_CALL") == 0 || strcmp(type, "R_ARM_THM_XPC22") == 0 ||
629
0
               strcmp(type, "R_ARM_THM_PC22") == 0) {
630
0
        value -= rel->section->offset + rel->offset;
631
0
        value += ((get_be16(location) & 0x7ff) << 12);
632
0
        value += (get_be16(location + 2) & 0x7ff) << 1;
633
634
0
        set_be16(location, 0xf000 + ((value >> 12) & 0x7ff));
635
0
        set_be16(location + 2, 0xf800 + ((value >> 1) & 0x7ff));
636
637
        //(b, 0xF000 + ((v - 1) / 2) * 0x10000);
638
        // set_be32(location, get_be32(location) + value / 4);
639
0
    } else if (0 == strcmp("R_ARM_ABS8", type)) {
640
0
        *location += value;
641
0
    } else
642
0
        super::relocate1(rel, location, value, type);
643
0
}
644
645
void ElfLinkerArmLE::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
646
0
                               const char *type) {
647
0
    if (!strcmp(type, "R_ARM_PC24") || !strcmp(type, "R_ARM_CALL") ||
648
0
        !strcmp(type, "R_ARM_JUMP24")) {
649
0
        value -= rel->section->offset + rel->offset;
650
0
        set_le24(location, get_le24(location) + value / 4);
651
0
    } else if (strcmp(type, "R_ARM_ABS32") == 0) {
652
0
        set_le32(location, get_le32(location) + value);
653
0
    } else if (strcmp(type, "R_ARM_THM_CALL") == 0 || strcmp(type, "R_ARM_THM_XPC22") == 0 ||
654
0
               strcmp(type, "R_ARM_THM_PC22") == 0) {
655
0
        value -= rel->section->offset + rel->offset;
656
0
        value += ((get_le16(location) & 0x7ff) << 12);
657
0
        value += (get_le16(location + 2) & 0x7ff) << 1;
658
659
0
        set_le16(location, 0xf000 + ((value >> 12) & 0x7ff));
660
0
        set_le16(location + 2, 0xf800 + ((value >> 1) & 0x7ff));
661
662
        //(b, 0xF000 + ((v - 1) / 2) * 0x10000);
663
        // set_le32(location, get_le32(location) + value / 4);
664
0
    } else if (0 == strcmp("R_ARM_ABS8", type)) {
665
0
        *location += value;
666
0
    } else
667
0
        super::relocate1(rel, location, value, type);
668
0
}
669
670
void ElfLinkerArm64LE::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
671
0
                                 const char *type) {
672
0
    if (strncmp(type, "R_AARCH64_", 10))
673
0
        return super::relocate1(rel, location, value, type);
674
0
    type += 10;
675
676
0
    if (!strncmp(type, "PREL", 4)) {
677
0
        value -= rel->section->offset + rel->offset;
678
0
        type += 4;
679
680
0
        if (!strcmp(type, "16"))
681
0
            set_le16(location, get_le16(location) + value);
682
0
        else if (!strncmp(type, "32", 2)) // for "32" and "32S"
683
0
            set_le32(location, get_le32(location) + value);
684
0
        else if (!strcmp(type, "64"))
685
0
            set_le64(location, get_le64(location) + value);
686
0
    } else if (!strcmp(type, "ADR_PREL_LO21")) {
687
0
        value -= rel->section->offset + rel->offset;
688
0
        upx_uint32_t const m19 = ~(~0u << 19);
689
0
        upx_uint32_t w = get_le32(location);
690
0
        set_le32(location, (w & ~((3u << 29) | (m19 << 5))) | ((3u & value) << 29) |
691
0
                               ((m19 & (value >> 2)) << 5));
692
0
    } else if (!strcmp(type, "ABS32")) {
693
0
        set_le32(location, get_le32(location) + value);
694
0
    } else if (!strcmp(type, "ABS64")) {
695
0
        set_le64(location, get_le64(location) + value);
696
0
    } else if (!strcmp(type, "CONDBR19")) {
697
0
        value -= rel->section->offset + rel->offset;
698
0
        upx_uint32_t const m19 = ~(~0u << 19);
699
0
        upx_uint32_t w = get_le32(location);
700
0
        set_le32(location, (w & ~(m19 << 5)) | ((((w >> 5) + (value >> 2)) & m19) << 5));
701
0
    } else if (!strcmp(type, "CALL26") || !strcmp(type, "JUMP26")) {
702
0
        value -= rel->section->offset + rel->offset;
703
0
        upx_uint32_t const m26 = ~(~0u << 26);
704
0
        upx_uint32_t w = get_le32(location);
705
0
        set_le32(location, (w & ~m26) | (m26 & (value >> 2)));
706
0
    } else
707
0
        super::relocate1(rel, location, value, type);
708
0
}
709
710
// clang-format off
711
unsigned extr_imm_RV_JAL(unsigned w);
712
unsigned extr_imm_RV_JAL(unsigned w)
713
0
{
714
0
    return ((0x3ff & (w >> 21)) << 1)
715
0
        | ((     1 & (w >> 20)) << 11)
716
0
        | ((  0xff & (w >> 12)) << 12)
717
0
        | ((     1 & (w >> 31)) << 20);
718
0
}
719
unsigned ins_imm_RV_JAL(unsigned w);
720
unsigned ins_imm_RV_JAL(unsigned w)
721
0
{
722
0
    return 0
723
0
        | (( 0x3ff & (w >>  1)) << 21)
724
0
        | ((     1 & (w >> 11)) << 20)
725
0
        | ((  0xff & (w >> 12)) << 12)
726
0
        | ((     1 & (w >> 20)) << 31);
727
0
}
728
729
unsigned extr_imm_RV_Bxx(unsigned w);
730
unsigned extr_imm_RV_Bxx(unsigned w)
731
0
{
732
0
    return 0
733
0
        | ((0xf & (w >>  8)) << 1)
734
0
        | ((077 & (w >> 25)) << 5)
735
0
        | ((  1 & (w >>  7)) << 11)
736
0
        | ((  1 & (w >> 31)) << 12);
737
0
}
738
unsigned ins_imm_RV_Bxx(unsigned w);
739
unsigned ins_imm_RV_Bxx(unsigned w)
740
0
{
741
0
    return 0
742
0
        | ((0xf & (w >>  1)) <<  8)
743
0
        | ((077 & (w >>  5)) << 25)
744
0
        | ((  1 & (w >> 11)) <<  7)
745
0
        | ((  1 & (w >> 12)) << 31);
746
0
}
747
748
unsigned extr_imm_RVC_Beq(unsigned w);
749
unsigned extr_imm_RVC_Beq(unsigned w)
750
0
{
751
0
    return ((3 & (w >>  3)) << 1)
752
0
        | (( 3 & (w >> 10)) << 3)
753
0
        | (( 1 & (w >>  2)) << 5)
754
0
        | (( 3 & (w >>  5)) << 6)
755
0
        | (( 1 & (w >> 12)) << 8);
756
0
}
757
unsigned ins_imm_RVC_Beq(unsigned w);
758
unsigned ins_imm_RVC_Beq(unsigned w)
759
0
{
760
0
    return 0
761
0
        | ((1 & (w >> 5)) <<  2)
762
0
        | ((3 & (w >> 1)) <<  3)
763
0
        | ((3 & (w >> 6)) <<  5)
764
0
        | ((3 & (w >> 3)) << 10)
765
0
        | ((1 & (w >> 8)) << 12);
766
0
}
767
768
unsigned extr_imm_RVC_Jmp(unsigned w);
769
unsigned extr_imm_RVC_Jmp(unsigned w)
770
0
{
771
0
    return ((7 & (w >>  3)) << 1)
772
0
        | (( 1 & (w >> 11)) << 4)
773
0
        | (( 1 & (w >>  2)) << 5)
774
0
        | (( 1 & (w >>  7)) << 6)
775
0
        | (( 1 & (w >>  6)) << 7)
776
0
        | (( 3 & (w >>  9)) << 8)
777
0
        | (( 1 & (w >>  8)) << 10)
778
0
        | (( 1 & (w >> 12)) << 11);
779
0
}
780
unsigned ins_imm_RVC_Jmp(unsigned w);
781
unsigned ins_imm_RVC_Jmp(unsigned w)
782
0
{
783
0
    return 0
784
0
        | ((7 & (w >>  1)) <<  3)
785
0
        | ((1 & (w >>  4)) << 11)
786
0
        | ((1 & (w >>  5)) <<  2)
787
0
        | ((1 & (w >>  6)) <<  7)
788
0
        | ((1 & (w >>  7)) <<  6)
789
0
        | ((3 & (w >>  8)) <<  9)
790
0
        | ((1 & (w >> 10)) <<  8)
791
0
        | ((1 & (w >> 11)) << 12);
792
0
}
793
794
#if 0  //{  RV32 only!
795
unsigned extr_imm_RVC_JAL(unsigned w);
796
unsigned extr_imm_RVC_JAL(unsigned w)  // RV32 only!
797
{
798
    return ((0x7 & (w >>  3)) <<  1)
799
        | ((   1 & (w >> 11)) <<  4)
800
        | ((   1 & (w >>  2)) <<  5)
801
        | ((   1 & (w >>  7)) <<  6)
802
        | ((   1 & (w >>  6)) <<  7)
803
        | ((   3 & (w >>  9)) <<  8)
804
        | ((   1 & (w >>  8)) << 10)
805
        | ((   1 & (w >> 11)) << 11) ;
806
}
807
unsigned ins_imm_RVC_JAL(unsigned w);
808
unsigned ins_imm_RVC_JAL(unsigned w)  // RV32 only!
809
{
810
    return ((0x7 & (w >>  1)) <<  3)
811
        | ((   1 & (w >>  4)) << 11)
812
        | ((   1 & (w >>  5)) <<  2)
813
        | ((   1 & (w >>  6)) <<  7)
814
        | ((   1 & (w >>  7)) <<  6)
815
        | ((   3 & (w >>  8)) <<  9)
816
        | ((   1 & (w >> 10)) <<  0)
817
        | ((   1 & (w >> 11)) << 11) ;
818
}
819
#endif  //}
820
// clang-format on
821
822
void ElfLinkerRiscv64LE::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
823
0
                                   const char *type) {
824
0
    if (strncmp(type, "R_RISCV_", 8)) // not us
825
0
        return super::relocate1(rel, location, value, type);
826
0
    type += 8;
827
828
0
    if (!strncmp(type, "BRANCH", 6)) {
829
0
        value -= rel->section->offset + rel->offset;
830
0
        unsigned instr = get_le32(location);
831
0
        set_le32(location,
832
0
                 (((037 << 20) | (037 << 15) | (7 << 12) | 0x7f) & instr) | ins_imm_RV_Bxx(value));
833
0
    } else if (!strncmp(type, "JAL", 3)) {
834
0
        value -= rel->section->offset + rel->offset;
835
0
        unsigned instr = get_le32(location);
836
0
        set_le32(location, (0xfff & instr) | ins_imm_RV_JAL(value));
837
0
    } else if (!strncmp(type, "RVC_BRANCH", 10)) {
838
0
        value -= rel->section->offset + rel->offset;
839
0
        unsigned instr = get_le16(location);
840
0
        set_le16(location, (((7 << 13) | (7 << 7) | 3) & instr) | ins_imm_RVC_Beq(value));
841
0
    } else if (!strncmp(type, "RVC_JUMP", 8)) {
842
0
        value -= rel->section->offset + rel->offset;
843
0
        unsigned instr = get_le16(location);
844
0
        set_le16(location, (((7 << 13) | 3) & instr) | ins_imm_RVC_Jmp(value));
845
0
    } else if (!strncmp(type, "32", 2)) {
846
0
        set_le32(location, value);
847
0
    } else
848
0
        super::relocate1(rel, location, value, type);
849
0
}
850
851
0
void ElfLinkerM68k::alignCode(unsigned len) {
852
0
    assert((len & 1) == 0);
853
0
    assert((outputlen & 1) == 0);
854
0
    for (unsigned i = 0; i < len; i += 2)
855
0
        set_be16(output + outputlen + i, 0x4e71); // "nop"
856
0
    outputlen += len;
857
0
}
858
859
void ElfLinkerM68k::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
860
0
                              const char *type) {
861
0
    if (strncmp(type, "R_68K_", 6))
862
0
        return super::relocate1(rel, location, value, type);
863
0
    type += 6;
864
865
0
    if (strncmp(type, "PC", 2) == 0) {
866
0
        value -= rel->section->offset + rel->offset;
867
0
        type += 2;
868
0
    }
869
0
    if (strcmp(type, "8") == 0) {
870
0
        *location += value;
871
0
    } else if (strcmp(type, "16") == 0) {
872
0
        set_be16(location, get_be16(location) + value);
873
0
    } else if (strcmp(type, "32") == 0) {
874
0
        set_be32(location, get_be32(location) + value);
875
0
    } else
876
0
        super::relocate1(rel, location, value, type);
877
0
}
878
879
void ElfLinkerMipsBE::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
880
0
                                const char *type) {
881
0
#define MIPS_HI(a)   (((a) >> 16) + (((a) &0x8000) >> 15))
882
0
#define MIPS_LO(a)   ((a) &0xffff)
883
0
#define MIPS_PC16(a) ((a) >> 2)
884
0
#define MIPS_PC26(a) (((a) &0x0fffffff) >> 2)
885
886
0
    if (strcmp(type, "R_MIPS_HI16") == 0)
887
0
        set_be16(2 + location, get_be16(2 + location) + MIPS_HI(value));
888
0
    else if (strcmp(type, "R_MIPS_LO16") == 0)
889
0
        set_be16(2 + location, get_be16(2 + location) + MIPS_LO(value));
890
0
    else if (strcmp(type, "R_MIPS_PC16") == 0) {
891
0
        value -= rel->section->offset + rel->offset;
892
0
        set_be16(2 + location, get_be16(2 + location) + MIPS_PC16(value));
893
0
    } else if (strcmp(type, "R_MIPS_26") == 0)
894
0
        set_be32(location, get_be32(location) + MIPS_PC26(value));
895
0
    else if (strcmp(type, "R_MIPS_32") == 0)
896
0
        set_be32(location, get_be32(location) + value);
897
0
    else
898
0
        super::relocate1(rel, location, value, type);
899
900
0
#undef MIPS_HI
901
0
#undef MIPS_LO
902
0
#undef MIPS_PC16
903
0
#undef MIPS_PC26
904
0
}
905
906
void ElfLinkerMipsLE::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
907
0
                                const char *type) {
908
0
#define MIPS_HI(a)   (((a) >> 16) + (((a) &0x8000) >> 15))
909
0
#define MIPS_LO(a)   ((a) &0xffff)
910
0
#define MIPS_PC16(a) ((a) >> 2)
911
0
#define MIPS_PC26(a) (((a) &0x0fffffff) >> 2)
912
913
0
    if (strcmp(type, "R_MIPS_HI16") == 0)
914
0
        set_le16(location, get_le16(location) + MIPS_HI(value));
915
0
    else if (strcmp(type, "R_MIPS_LO16") == 0)
916
0
        set_le16(location, get_le16(location) + MIPS_LO(value));
917
0
    else if (strcmp(type, "R_MIPS_PC16") == 0) {
918
0
        value -= rel->section->offset + rel->offset;
919
0
        set_le16(location, get_le16(location) + MIPS_PC16(value));
920
0
    } else if (strcmp(type, "R_MIPS_26") == 0)
921
0
        set_le32(location, get_le32(location) + MIPS_PC26(value));
922
0
    else if (strcmp(type, "R_MIPS_32") == 0)
923
0
        set_le32(location, get_le32(location) + value);
924
0
    else
925
0
        super::relocate1(rel, location, value, type);
926
927
0
#undef MIPS_HI
928
0
#undef MIPS_LO
929
0
#undef MIPS_PC16
930
0
#undef MIPS_PC26
931
0
}
932
933
void ElfLinkerPpc32::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
934
0
                               const char *type) {
935
0
    if (strncmp(type, "R_PPC_", 6))
936
0
        return super::relocate1(rel, location, value, type);
937
0
    type += 6;
938
939
0
    if (strcmp(type, "ADDR32") == 0) {
940
0
        set_be32(location, get_be32(location) + value);
941
0
        return;
942
0
    }
943
944
0
    if (strncmp(type, "REL", 3) == 0) {
945
0
        value -= rel->section->offset + rel->offset;
946
0
        type += 3;
947
0
    }
948
949
    // FIXME: more relocs
950
951
    // Note that original (*location).displ is ignored.
952
0
    if (strcmp(type, "24") == 0) {
953
0
        if (3 & value)
954
0
            throwInternalError("unaligned word displacement");
955
        // FIXME: displacement overflow?
956
0
        set_be32(location, (0xfc000003 & get_be32(location)) + (0x03fffffc & value));
957
0
    } else if (strcmp(type, "14") == 0) {
958
0
        if (3 & value)
959
0
            throwInternalError("unaligned word displacement");
960
        // FIXME: displacement overflow?
961
0
        set_be32(location, (0xffff0003 & get_be32(location)) + (0x0000fffc & value));
962
0
    } else
963
0
        super::relocate1(rel, location, value, type);
964
0
}
965
966
void ElfLinkerPpc64le::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
967
0
                                 const char *type) {
968
0
    if (!strcmp(type, "R_PPC64_ADDR64")) {
969
0
        set_le64(location, get_le64(location) + value);
970
0
        return;
971
0
    }
972
0
    if (!strcmp(type, "R_PPC64_ADDR32")) {
973
0
        set_le32(location, get_le32(location) + value);
974
0
        return;
975
0
    }
976
0
    if (strncmp(type, "R_PPC64_REL", 11))
977
0
        return super::relocate1(rel, location, value, type);
978
0
    type += 11;
979
980
0
    bool range_check = false;
981
0
    if (strncmp(type, "PC", 2) == 0) {
982
0
        type += 2;
983
0
        range_check = true;
984
0
    }
985
986
    /* value will hold relative displacement */
987
0
    value -= rel->section->offset + rel->offset;
988
989
0
    if (strncmp(type, "14", 2) == 0) { // for "14" and "14S"
990
0
        if (3 & value)
991
0
            throwInternalError("unaligned word displacement");
992
        // FIXME: displacement overflow?
993
0
        set_le32(location, (0xffff0003 & get_le32(location)) + (0x0000fffc & value));
994
0
    } else if (strncmp(type, "24", 2) == 0) { // for "24" and "24S"
995
0
        if (3 & value)
996
0
            throwInternalError("unaligned word displacement");
997
        // FIXME: displacement overflow?
998
0
        set_le32(location, (0xfc000003 & get_le32(location)) + (0x03fffffc & value));
999
0
    } else if (strcmp(type, "8") == 0) {
1000
0
        int displ = (upx_int8_t) *location + (int) value;
1001
0
        if (range_check && (displ < -128 || displ > 127))
1002
0
            throwInternalError("target out of range (%d) in reloc %s:%x\n", displ,
1003
0
                               rel->section->name, rel->offset);
1004
0
        *location += value;
1005
0
    } else if (strcmp(type, "16") == 0)
1006
0
        set_le16(location, get_le16(location) + value);
1007
0
    else if (strncmp(type, "32", 2) == 0) // for "32" and "32S"
1008
0
        set_le32(location, get_le32(location) + value);
1009
0
    else if (strcmp(type, "64") == 0)
1010
0
        set_le64(location, get_le64(location) + value);
1011
0
    else
1012
0
        super::relocate1(rel, location, value, type);
1013
0
}
1014
1015
void ElfLinkerPpc64::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
1016
0
                               const char *type) {
1017
0
    if (!strcmp(type, "R_PPC64_ADDR32")) {
1018
0
        set_be32(location, get_be32(location) + value);
1019
0
        return;
1020
0
    }
1021
0
    if (!strcmp(type, "R_PPC64_ADDR64")) {
1022
0
        set_be64(location, get_be64(location) + value);
1023
0
        return;
1024
0
    }
1025
0
    if (strncmp(type, "R_PPC64_REL", 11))
1026
0
        return super::relocate1(rel, location, value, type);
1027
0
    type += 11;
1028
1029
0
    bool range_check = false;
1030
0
    if (strncmp(type, "PC", 2) == 0) {
1031
0
        type += 2;
1032
0
        range_check = true;
1033
0
    }
1034
1035
    // We have "R_PPC64_REL" or "R_PPC64_RELPC" as a prefix.
1036
    /* value will hold relative displacement */
1037
0
    value -= rel->section->offset + rel->offset;
1038
1039
0
    if (strncmp(type, "14", 2) == 0) { // for "14" and "14S"
1040
0
        if (3 & value)
1041
0
            throwInternalError("unaligned word displacement");
1042
        // FIXME: displacement overflow?
1043
0
        set_be32(location, (0xffff0003 & get_be32(location)) + (0x0000fffc & value));
1044
0
    } else if (strncmp(type, "24", 2) == 0) { // for "24" and "24S"
1045
0
        if (3 & value)
1046
0
            throwInternalError("unaligned word displacement");
1047
        // FIXME: displacement overflow?
1048
0
        set_be32(location, (0xfc000003 & get_be32(location)) + (0x03fffffc & value));
1049
0
    } else if (strcmp(type, "8") == 0) {
1050
0
        int displ = (upx_int8_t) *location + (int) value;
1051
0
        if (range_check && (displ < -128 || displ > 127))
1052
0
            throwInternalError("target out of range (%d) in reloc %s:%x\n", displ,
1053
0
                               rel->section->name, rel->offset);
1054
0
        *location += value;
1055
0
    } else if (strcmp(type, "16") == 0)
1056
0
        set_be16(location, get_be16(location) + value);
1057
0
    else if (strncmp(type, "32", 2) == 0) // for "32" and "32S"
1058
0
        set_be32(location, get_be32(location) + value);
1059
0
    else if (strcmp(type, "64") == 0)
1060
0
        set_be64(location, get_be64(location) + value);
1061
0
    else
1062
0
        super::relocate1(rel, location, value, type);
1063
0
}
1064
1065
void ElfLinkerX86::relocate1(const Relocation *rel, byte *location, upx_uint64_t value,
1066
0
                             const char *type) {
1067
0
    if (strncmp(type, "R_386_", 6))
1068
0
        return super::relocate1(rel, location, value, type);
1069
0
    type += 6;
1070
1071
0
    bool range_check = false;
1072
0
    if (strncmp(type, "PC", 2) == 0) {
1073
0
        value -= rel->section->offset + rel->offset;
1074
0
        type += 2;
1075
0
        range_check = true;
1076
0
    }
1077
1078
0
    if (strcmp(type, "8") == 0) {
1079
0
        int displ = (upx_int8_t) *location + (int) value;
1080
0
        if (range_check && (displ < -128 || displ > 127))
1081
0
            throwInternalError("target out of range (%d,%d,%llu) in reloc %s:%x\n", displ,
1082
0
                               *location, value, rel->section->name, rel->offset);
1083
0
        *location += value;
1084
0
    } else if (strcmp(type, "16") == 0)
1085
0
        set_le16(location, get_le16(location) + value);
1086
0
    else if (strcmp(type, "32") == 0)
1087
0
        set_le32(location, get_le32(location) + value);
1088
0
    else
1089
0
        super::relocate1(rel, location, value, type);
1090
0
}
1091
1092
/* vim:set ts=4 sw=4 et: */