summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/ldr_ro/cro_helper.h
blob: 060d5a55f4ef7cc7aa6268cdb571fc457b28fc89 (plain) (blame)
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <array>
#include <tuple>
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/result.h"
#include "core/memory.h"

namespace Service {
namespace LDR {

// GCC versions < 5.0 do not implement std::is_trivially_copyable.
// Excluding MSVC because it has weird behaviour for std::is_trivially_copyable.
#if (__GNUC__ >= 5) || defined(__clang__)
#define ASSERT_CRO_STRUCT(name, size)                                                              \
    static_assert(std::is_standard_layout<name>::value,                                            \
                  "CRO structure " #name " doesn't use standard layout");                          \
    static_assert(std::is_trivially_copyable<name>::value,                                         \
                  "CRO structure " #name " isn't trivially copyable");                             \
    static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name)
#else
#define ASSERT_CRO_STRUCT(name, size)                                                              \
    static_assert(std::is_standard_layout<name>::value,                                            \
                  "CRO structure " #name " doesn't use standard layout");                          \
    static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name)
#endif

static constexpr u32 CRO_HEADER_SIZE = 0x138;
static constexpr u32 CRO_HASH_SIZE = 0x80;

/// Represents a loaded module (CRO) with interfaces manipulating it.
class CROHelper final {
public:
    explicit CROHelper(VAddr cro_address) : module_address(cro_address) {}

    std::string ModuleName() const {
        return Memory::ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize));
    }

    u32 GetFileSize() const {
        return GetField(FileSize);
    }

    /**
     * Rebases the module according to its address.
     * @param crs_address the virtual address of the static module
     * @param cro_size the size of the CRO file
     * @param data_segment_address buffer address for .data segment
     * @param data_segment_size the buffer size for .data segment
     * @param bss_segment_address the buffer address for .bss segment
     * @param bss_segment_size the buffer size for .bss segment
     * @param is_crs true if the module itself is the static module
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment_addresss,
                      u32 data_segment_size, VAddr bss_segment_address, u32 bss_segment_size,
                      bool is_crs);

    /**
     * Unrebases the module.
     * @param is_crs true if the module itself is the static module
     */
    void Unrebase(bool is_crs);

    /**
     * Verifies module hash by CRR.
     * @param cro_size the size of the CRO
     * @param crr the virtual address of the CRR
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode VerifyHash(u32 cro_size, VAddr crr) const;

    /**
     * Links this module with all registered auto-link module.
     * @param crs_address the virtual address of the static module
     * @param link_on_load_bug_fix true if links when loading and fixes the bug
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode Link(VAddr crs_address, bool link_on_load_bug_fix);

    /**
     * Unlinks this module with other modules.
     * @param crs_address the virtual address of the static module
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode Unlink(VAddr crs_address);

    /**
     * Clears all relocations to zero.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ClearRelocations();

    /// Initialize this module as the static module (CRS)
    void InitCRS();

    /**
     * Registers this module and adds it to the module list.
     * @param crs_address the virtual address of the static module
     * @auto_link whether to register as an auto link module
     */
    void Register(VAddr crs_address, bool auto_link);

    /**
     * Unregisters this module and removes from the module list.
     * @param crs_address the virtual address of the static module
     */
    void Unregister(VAddr crs_address);

    /**
     * Gets the end of reserved data according to the fix level.
     * @param fix_level fix level from 0 to 3
     * @returns the end of reserved data.
     */
    u32 GetFixEnd(u32 fix_level) const;

    /**
     * Zeros offsets to cropped data according to the fix level and marks as fixed.
     * @param fix_level fix level from 0 to 3
     * @returns page-aligned size of the module after fixing.
     */
    u32 Fix(u32 fix_level);

    bool IsFixed() const {
        return GetField(Magic) == MAGIC_FIXD;
    }

    u32 GetFixedSize() const {
        return GetField(FixedSize);
    }

    bool IsLoaded() const;

    /**
     * Gets the page address and size of the code segment.
     * @returns a tuple of (address, size); (0, 0) if the code segment doesn't exist.
     */
    std::tuple<VAddr, u32> GetExecutablePages() const;

private:
    const VAddr module_address; ///< the virtual address of this module

    /**
     * Each item in this enum represents a u32 field in the header begin from address+0x80,
     * successively. We don't directly use a struct here, to avoid GetPointer, reinterpret_cast, or
     * Read/WriteBlock repeatedly.
     */
    enum HeaderField {
        Magic = 0,
        NameOffset,
        NextCRO,
        PreviousCRO,
        FileSize,
        BssSize,
        FixedSize,
        UnknownZero,
        UnkSegmentTag,
        OnLoadSegmentTag,
        OnExitSegmentTag,
        OnUnresolvedSegmentTag,

        CodeOffset,
        CodeSize,
        DataOffset,
        DataSize,
        ModuleNameOffset,
        ModuleNameSize,
        SegmentTableOffset,
        SegmentNum,

        ExportNamedSymbolTableOffset,
        ExportNamedSymbolNum,
        ExportIndexedSymbolTableOffset,
        ExportIndexedSymbolNum,
        ExportStringsOffset,
        ExportStringsSize,
        ExportTreeTableOffset,
        ExportTreeNum,

        ImportModuleTableOffset,
        ImportModuleNum,
        ExternalRelocationTableOffset,
        ExternalRelocationNum,
        ImportNamedSymbolTableOffset,
        ImportNamedSymbolNum,
        ImportIndexedSymbolTableOffset,
        ImportIndexedSymbolNum,
        ImportAnonymousSymbolTableOffset,
        ImportAnonymousSymbolNum,
        ImportStringsOffset,
        ImportStringsSize,

        StaticAnonymousSymbolTableOffset,
        StaticAnonymousSymbolNum,
        InternalRelocationTableOffset,
        InternalRelocationNum,
        StaticRelocationTableOffset,
        StaticRelocationNum,
        Fix0Barrier,

        Fix3Barrier = ExportNamedSymbolTableOffset,
        Fix2Barrier = ImportModuleTableOffset,
        Fix1Barrier = StaticAnonymousSymbolTableOffset,
    };
    static_assert(Fix0Barrier == (CRO_HEADER_SIZE - CRO_HASH_SIZE) / 4,
                  "CRO Header fields are wrong!");

    enum class SegmentType : u32 {
        Code = 0,
        ROData = 1,
        Data = 2,
        BSS = 3,
    };

    /**
     * Identifies a program location inside of a segment.
     * Required to refer to program locations because individual segments may be relocated
     * independently of each other.
     */
    union SegmentTag {
        u32_le raw;
        BitField<0, 4, u32_le> segment_index;
        BitField<4, 28, u32_le> offset_into_segment;

        SegmentTag() = default;
        explicit SegmentTag(u32 raw_) : raw(raw_) {}
    };

    /// Information of a segment in this module.
    struct SegmentEntry {
        u32_le offset;
        u32_le size;
        SegmentType type;

        static constexpr HeaderField TABLE_OFFSET_FIELD = SegmentTableOffset;
    };
    ASSERT_CRO_STRUCT(SegmentEntry, 12);

    /// Identifies a named symbol exported from this module.
    struct ExportNamedSymbolEntry {
        u32_le name_offset;         // pointing to a substring in ExportStrings
        SegmentTag symbol_position; // to self's segment

        static constexpr HeaderField TABLE_OFFSET_FIELD = ExportNamedSymbolTableOffset;
    };
    ASSERT_CRO_STRUCT(ExportNamedSymbolEntry, 8);

    /// Identifies an indexed symbol exported from this module.
    struct ExportIndexedSymbolEntry {
        SegmentTag symbol_position; // to self's segment

        static constexpr HeaderField TABLE_OFFSET_FIELD = ExportIndexedSymbolTableOffset;
    };
    ASSERT_CRO_STRUCT(ExportIndexedSymbolEntry, 4);

    /// A tree node in the symbol lookup tree.
    struct ExportTreeEntry {
        u16_le test_bit; // bit address into the name to test
        union Child {
            u16_le raw;
            BitField<0, 15, u16_le> next_index;
            BitField<15, 1, u16_le> is_end;
        } left, right;
        u16_le export_table_index; // index of an ExportNamedSymbolEntry

        static constexpr HeaderField TABLE_OFFSET_FIELD = ExportTreeTableOffset;
    };
    ASSERT_CRO_STRUCT(ExportTreeEntry, 8);

    /// Identifies a named symbol imported from another module.
    struct ImportNamedSymbolEntry {
        u32_le name_offset;             // pointing to a substring in ImportStrings
        u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable

        static constexpr HeaderField TABLE_OFFSET_FIELD = ImportNamedSymbolTableOffset;
    };
    ASSERT_CRO_STRUCT(ImportNamedSymbolEntry, 8);

    /// Identifies an indexed symbol imported from another module.
    struct ImportIndexedSymbolEntry {
        u32_le index; // index of an ExportIndexedSymbolEntry in the exporting module
        u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable

        static constexpr HeaderField TABLE_OFFSET_FIELD = ImportIndexedSymbolTableOffset;
    };
    ASSERT_CRO_STRUCT(ImportIndexedSymbolEntry, 8);

    /// Identifies an anonymous symbol imported from another module.
    struct ImportAnonymousSymbolEntry {
        SegmentTag symbol_position;     // in the exporting segment
        u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable

        static constexpr HeaderField TABLE_OFFSET_FIELD = ImportAnonymousSymbolTableOffset;
    };
    ASSERT_CRO_STRUCT(ImportAnonymousSymbolEntry, 8);

    /// Information of a imported module and symbols imported from it.
    struct ImportModuleEntry {
        u32_le name_offset;                        // pointing to a substring in ImportStrings
        u32_le import_indexed_symbol_table_offset; // pointing to a subtable in
                                                   // ImportIndexedSymbolTable
        u32_le import_indexed_symbol_num;
        u32_le import_anonymous_symbol_table_offset; // pointing to a subtable in
                                                     // ImportAnonymousSymbolTable
        u32_le import_anonymous_symbol_num;

        static constexpr HeaderField TABLE_OFFSET_FIELD = ImportModuleTableOffset;

        void GetImportIndexedSymbolEntry(u32 index, ImportIndexedSymbolEntry& entry) {
            Memory::ReadBlock(import_indexed_symbol_table_offset +
                                  index * sizeof(ImportIndexedSymbolEntry),
                              &entry, sizeof(ImportIndexedSymbolEntry));
        }

        void GetImportAnonymousSymbolEntry(u32 index, ImportAnonymousSymbolEntry& entry) {
            Memory::ReadBlock(import_anonymous_symbol_table_offset +
                                  index * sizeof(ImportAnonymousSymbolEntry),
                              &entry, sizeof(ImportAnonymousSymbolEntry));
        }
    };
    ASSERT_CRO_STRUCT(ImportModuleEntry, 20);

    enum class RelocationType : u8 {
        Nothing = 0,
        AbsoluteAddress = 2,
        RelativeAddress = 3,
        ThumbBranch = 10,
        ArmBranch = 28,
        ModifyArmBranch = 29,
        AbsoluteAddress2 = 38,
        AlignedRelativeAddress = 42,
    };

    struct RelocationEntry {
        SegmentTag target_position; // to self's segment as an ExternalRelocationEntry; to static
                                    // module segment as a StaticRelocationEntry
        RelocationType type;
        u8 is_batch_end;
        u8 is_batch_resolved; // set at a batch beginning if the batch is resolved
        INSERT_PADDING_BYTES(1);
        u32_le addend;
    };

    /// Identifies a normal cross-module relocation.
    struct ExternalRelocationEntry : RelocationEntry {
        static constexpr HeaderField TABLE_OFFSET_FIELD = ExternalRelocationTableOffset;
    };
    ASSERT_CRO_STRUCT(ExternalRelocationEntry, 12);

    /// Identifies a special static relocation (no game is known using this).
    struct StaticRelocationEntry : RelocationEntry {
        static constexpr HeaderField TABLE_OFFSET_FIELD = StaticRelocationTableOffset;
    };
    ASSERT_CRO_STRUCT(StaticRelocationEntry, 12);

    /// Identifies a in-module relocation.
    struct InternalRelocationEntry {
        SegmentTag target_position; // to self's segment
        RelocationType type;
        u8 symbol_segment;
        INSERT_PADDING_BYTES(2);
        u32_le addend;

        static constexpr HeaderField TABLE_OFFSET_FIELD = InternalRelocationTableOffset;
    };
    ASSERT_CRO_STRUCT(InternalRelocationEntry, 12);

    /// Identifies a special static anonymous symbol (no game is known using this).
    struct StaticAnonymousSymbolEntry {
        SegmentTag symbol_position;     // to self's segment
        u32_le relocation_batch_offset; // pointing to a relocation batch in StaticRelocationTable

        static constexpr HeaderField TABLE_OFFSET_FIELD = StaticAnonymousSymbolTableOffset;
    };
    ASSERT_CRO_STRUCT(StaticAnonymousSymbolEntry, 8);

    /**
     * Entry size of each table, from Code to StaticRelocationTable.
     * Byte string contents (such as Code) are treated with entries of size 1.
     * This is used for verifying the size of each table and calculating the fix end.
     */
    static const std::array<int, 17> ENTRY_SIZE;

    /// The offset field of the table where to crop for each fix level
    static const std::array<HeaderField, 4> FIX_BARRIERS;

    static constexpr u32 MAGIC_CRO0 = 0x304F5243;
    static constexpr u32 MAGIC_FIXD = 0x44584946;

    VAddr Field(HeaderField field) const {
        return module_address + CRO_HASH_SIZE + field * 4;
    }

    u32 GetField(HeaderField field) const {
        return Memory::Read32(Field(field));
    }

    void SetField(HeaderField field, u32 value) {
        Memory::Write32(Field(field), value);
    }

    /**
     * Reads an entry in one of module tables.
     * @param index index of the entry
     * @param data where to put the read entry
     * @note the entry type must have the static member TABLE_OFFSET_FIELD
     *       indicating which table the entry is in.
     */
    template <typename T>
    void GetEntry(std::size_t index, T& data) const {
        Memory::ReadBlock(GetField(T::TABLE_OFFSET_FIELD) + index * sizeof(T), &data, sizeof(T));
    }

    /**
     * Writes an entry to one of module tables.
     * @param index index of the entry
     * @param data the entry data to write
     * @note the entry type must have the static member TABLE_OFFSET_FIELD
     *       indicating which table the entry is in.
     */
    template <typename T>
    void SetEntry(std::size_t index, const T& data) {
        Memory::WriteBlock(GetField(T::TABLE_OFFSET_FIELD) + index * sizeof(T), &data, sizeof(T));
    }

    /**
     * Converts a segment tag to virtual address in this module.
     * @param segment_tag the segment tag to convert
     * @returns VAddr the virtual address the segment tag points to; 0 if invalid.
     */
    VAddr SegmentTagToAddress(SegmentTag segment_tag) const;

    VAddr NextModule() const {
        return GetField(NextCRO);
    }

    VAddr PreviousModule() const {
        return GetField(PreviousCRO);
    }

    void SetNextModule(VAddr next) {
        SetField(NextCRO, next);
    }

    void SetPreviousModule(VAddr previous) {
        SetField(PreviousCRO, previous);
    }

    /**
     * A helper function iterating over all registered auto-link modules, including the static
     * module.
     * @param crs_address the virtual address of the static module
     * @param func a function object to operate on a module. It accepts one parameter
     *        CROHelper and returns ResultVal<bool>. It should return true to continue the
     * iteration,
     *        false to stop the iteration, or an error code (which will also stop the iteration).
     * @returns ResultCode indicating the result of the operation, RESULT_SUCCESS if all iteration
     * success,
     *         otherwise error code of the last iteration.
     */
    template <typename FunctionObject>
    static ResultCode ForEachAutoLinkCRO(VAddr crs_address, FunctionObject func) {
        VAddr current = crs_address;
        while (current != 0) {
            CROHelper cro(current);
            CASCADE_RESULT(bool next, func(cro));
            if (!next)
                break;
            current = cro.NextModule();
        }
        return RESULT_SUCCESS;
    }

    /**
     * Applies a relocation
     * @param target_address where to apply the relocation
     * @param relocation_type the type of the relocation
     * @param addend address addend applied to the relocated symbol
     * @param symbol_address the symbol address to be relocated with
     * @param target_future_address the future address of the target.
     *        Usually equals to target_address, but will be different for a target in .data segment
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ApplyRelocation(VAddr target_address, RelocationType relocation_type, u32 addend,
                               u32 symbol_address, u32 target_future_address);

    /**
     * Clears a relocation to zero
     * @param target_address where to apply the relocation
     * @param relocation_type the type of the relocation
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ClearRelocation(VAddr target_address, RelocationType relocation_type);

    /**
     * Applies or resets a batch of relocations
     * @param batch the virtual address of the first relocation in the batch
     * @param symbol_address the symbol address to be relocated with
     * @param reset false to set the batch to resolved state, true to reset the batch to unresolved
     * state
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool reset = false);

    /**
     * Finds an exported named symbol in this module.
     * @param name the name of the symbol to find
     * @return VAddr the virtual address of the symbol; 0 if not found.
     */
    VAddr FindExportNamedSymbol(const std::string& name) const;

    /**
     * Rebases offsets in module header according to module address.
     * @param cro_size the size of the CRO file
     * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
     * code.
     */
    ResultCode RebaseHeader(u32 cro_size);

    /**
     * Rebases offsets in segment table according to module address.
     * @param cro_size the size of the CRO file
     * @param data_segment_address the buffer address for .data segment
     * @param data_segment_size the buffer size for .data segment
     * @param bss_segment_address the buffer address for .bss segment
     * @param bss_segment_size the buffer size for .bss segment
     * @returns ResultVal<VAddr> with the virtual address of .data segment in CRO.
     */
    ResultVal<VAddr> RebaseSegmentTable(u32 cro_size, VAddr data_segment_address,
                                        u32 data_segment_size, VAddr bss_segment_address,
                                        u32 bss_segment_size);

    /**
     * Rebases offsets in exported named symbol table according to module address.
     * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
     * code.
     */
    ResultCode RebaseExportNamedSymbolTable();

    /**
     * Verifies indices in export tree table.
     * @returns ResultCode RESULT_SUCCESS if all indices are verified as valid, otherwise error
     * code.
     */
    ResultCode VerifyExportTreeTable() const;

    /**
     * Rebases offsets in exported module table according to module address.
     * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
     * code.
     */
    ResultCode RebaseImportModuleTable();

    /**
     * Rebases offsets in imported named symbol table according to module address.
     * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
     * code.
     */
    ResultCode RebaseImportNamedSymbolTable();

    /**
     * Rebases offsets in imported indexed symbol table according to module address.
     * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
     * code.
     */
    ResultCode RebaseImportIndexedSymbolTable();

    /**
     * Rebases offsets in imported anonymous symbol table according to module address.
     * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
     * code.
     */
    ResultCode RebaseImportAnonymousSymbolTable();

    /**
     * Gets the address of OnUnresolved function in this module.
     * Used as the applied symbol for reset relocation.
     * @returns the virtual address of OnUnresolved. 0 if not provided.
     */
    VAddr GetOnUnresolvedAddress();

    /**
     * Resets all external relocations to unresolved state.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ResetExternalRelocations();

    /**
     * Clears all external relocations to zero.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ClearExternalRelocations();

    /**
     * Applies all static anonymous symbol to the static module.
     * @param crs_address the virtual address of the static module
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ApplyStaticAnonymousSymbolToCRS(VAddr crs_address);

    /**
     * Applies all internal relocations to the module itself.
     * @param old_data_segment_address the virtual address of data segment in CRO buffer
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ApplyInternalRelocations(u32 old_data_segment_address);

    /**
     * Clears all internal relocations to zero.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ClearInternalRelocations();

    /// Unrebases offsets in imported anonymous symbol table
    void UnrebaseImportAnonymousSymbolTable();

    /// Unrebases offsets in imported indexed symbol table
    void UnrebaseImportIndexedSymbolTable();

    /// Unrebases offsets in imported named symbol table
    void UnrebaseImportNamedSymbolTable();

    /// Unrebases offsets in imported module table
    void UnrebaseImportModuleTable();

    /// Unrebases offsets in exported named symbol table
    void UnrebaseExportNamedSymbolTable();

    /// Unrebases offsets in segment table
    void UnrebaseSegmentTable();

    /// Unrebases offsets in module header
    void UnrebaseHeader();

    /**
     * Looks up all imported named symbols of this module in all registered auto-link modules, and
     * resolves them if found.
     * @param crs_address the virtual address of the static module
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ApplyImportNamedSymbol(VAddr crs_address);

    /**
     * Resets all imported named symbols of this module to unresolved state.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ResetImportNamedSymbol();

    /**
     * Resets all imported indexed symbols of this module to unresolved state.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ResetImportIndexedSymbol();

    /**
     * Resets all imported anonymous symbols of this module to unresolved state.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ResetImportAnonymousSymbol();

    /**
     * Finds registered auto-link modules that this module imports, and resolves indexed and
     * anonymous symbols exported by them.
     * @param crs_address the virtual address of the static module
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ApplyModuleImport(VAddr crs_address);

    /**
     * Resolves target module's imported named symbols that exported by this module.
     * @param target the module to resolve.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ApplyExportNamedSymbol(CROHelper target);

    /**
     * Resets target's named symbols imported from this module to unresolved state.
     * @param target the module to reset.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ResetExportNamedSymbol(CROHelper target);

    /**
     * Resolves imported indexed and anonymous symbols in the target module which imports this
     * module.
     * @param target the module to resolve.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ApplyModuleExport(CROHelper target);

    /**
     * Resets target's indexed and anonymous symbol imported from this module to unresolved state.
     * @param target the module to reset.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ResetModuleExport(CROHelper target);

    /**
     * Resolves the exit function in this module
     * @param crs_address the virtual address of the static module.
     * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
     */
    ResultCode ApplyExitRelocations(VAddr crs_address);
};

} // namespace LDR
} // namespace Service