odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

asmjit_test_x86_sections.cpp (5623B)


      1 // This file is part of AsmJit project <https://asmjit.com>
      2 //
      3 // See <asmjit/core.h> or LICENSE.md for license and copyright information
      4 // SPDX-License-Identifier: Zlib
      5 
      6 // ----------------------------------------------------------------------------
      7 // This is a working example that demonstrates how multiple sections can be
      8 // used in a JIT-based code generator. It shows also the necessary tooling
      9 // that is expected to be done by the user when the feature is used. It's
     10 // important to handle the following cases:
     11 //
     12 //   - Assign offsets to sections when the code generation is finished.
     13 //   - Tell the CodeHolder to resolve unresolved fixups and check whether
     14 //     all fixups were resolved.
     15 //   - Relocate the code
     16 //   - Copy the code to the destination address.
     17 // ----------------------------------------------------------------------------
     18 
     19 #include <asmjit/core.h>
     20 #if ASMJIT_ARCH_X86 && !defined(ASMJIT_NO_X86) && !defined(ASMJIT_NO_JIT)
     21 
     22 #include <asmjit/x86.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 
     27 using namespace asmjit;
     28 
     29 // The generated function is very simple, it only accesses the built-in data
     30 // (from .data section) at the index as provided by its first argument. This
     31 // data is inlined into the resulting function so we can use it this array
     32 // for verification that the function returns correct values.
     33 static const uint8_t data_array[] = { 2, 9, 4, 7, 1, 3, 8, 5, 6, 0 };
     34 
     35 static void fail(const char* message, Error err) {
     36   printf("** FAILURE: %s (%s) **\n", message, DebugUtils::error_as_string(err));
     37   exit(1);
     38 }
     39 
     40 int main() {
     41   printf("AsmJit X86 Sections Test\n\n");
     42 
     43   Environment env = Environment::host();
     44   JitAllocator allocator;
     45 
     46 #ifndef ASMJIT_NO_LOGGING
     47   FileLogger logger(stdout);
     48   logger.set_indentation(FormatIndentationGroup::kCode, 2);
     49 #endif
     50 
     51   CodeHolder code;
     52   code.init(env);
     53 
     54 #ifndef ASMJIT_NO_LOGGING
     55   code.set_logger(&logger);
     56 #endif
     57 
     58   Section* data_section;
     59   Error err = code.new_section(Out(data_section), ".data", SIZE_MAX, SectionFlags::kNone, 8);
     60 
     61   if (err != Error::kOk) {
     62     fail("Failed to create a .data section", err);
     63   }
     64   else {
     65     printf("Generating code:\n");
     66     x86::Assembler a(&code);
     67     x86::Gp idx = a.zax();
     68     x86::Gp addr = a.zcx();
     69 
     70     Label data = a.new_label();
     71 
     72     FuncDetail func;
     73     func.init(FuncSignature::build<size_t, size_t>(), code.environment());
     74 
     75     FuncFrame frame;
     76     frame.init(func);
     77     frame.add_dirty_regs(idx, addr);
     78 
     79     FuncArgsAssignment args(&func);
     80     args.assign_all(idx);
     81     args.update_func_frame(frame);
     82     frame.finalize();
     83 
     84     a.emit_prolog(frame);
     85     a.emit_args_assignment(frame, args);
     86 
     87     a.lea(addr, x86::ptr(data));
     88     a.movzx(idx, x86::byte_ptr(addr, idx));
     89 
     90     a.emit_epilog(frame);
     91 
     92     a.section(data_section);
     93     a.bind(data);
     94 
     95     a.embed(data_array, sizeof(data_array));
     96   }
     97 
     98   // Manually change he offsets of each section, start at 0. This code is very similar to
     99   // what `CodeHolder::flatten()` does, however, it's shown here how to do it explicitly.
    100   printf("\nCalculating section offsets:\n");
    101   uint64_t offset = 0;
    102   for (Section* section : code.sections_by_order()) {
    103     offset = Support::align_up(offset, section->alignment());
    104     section->set_offset(offset);
    105     offset += section->real_size();
    106 
    107     printf("  [0x%08X %s] {Id=%u Size=%u}\n",
    108            uint32_t(section->offset()),
    109            section->name(),
    110            section->section_id(),
    111            uint32_t(section->real_size()));
    112   }
    113   size_t code_size = size_t(offset);
    114   printf("  Final code size: %zu\n", code_size);
    115 
    116   // Resolve cross-section fixups (if any). On 32-bit X86 this is not necessary
    117   // as this is handled through relocations as the addressing is different.
    118   if (code.has_unresolved_fixups()) {
    119     printf("\nResolving cross-section fixups:\n");
    120     printf("  Before 'resolve_cross_section_fixups()': %zu\n", code.unresolved_fixup_count());
    121 
    122     err = code.resolve_cross_section_fixups();
    123     if (err != Error::kOk) {
    124       fail("Failed to resolve cross-section fixups", err);
    125     }
    126     printf("  After 'resolve_cross_section_fixups()': %zu\n", code.unresolved_fixup_count());
    127   }
    128 
    129   // Allocate memory for the function and relocate it there.
    130   JitAllocator::Span span;
    131   err = allocator.alloc(Out(span), code_size);
    132   if (err != Error::kOk)
    133     fail("Failed to allocate executable memory", err);
    134 
    135   // Relocate to the base-address of the allocated memory.
    136   code.relocate_to_base(uint64_t(uintptr_t(span.rx())));
    137 
    138   allocator.write(span, [&](JitAllocator::Span& span) noexcept -> Error {
    139     // Copy the flattened code into `mem.rw`. There are two ways. You can either copy
    140     // everything manually by iterating over all sections or use `copy_flattened_data`.
    141     // This code is similar to what `copy_flattened_data(p, code_size, 0)` would do:
    142     for (Section* section : code.sections_by_order())
    143       memcpy(static_cast<uint8_t*>(span.rw()) + size_t(section->offset()), section->data(), section->buffer_size());
    144     return Error::kOk;
    145   });
    146 
    147   // Execute the function and test whether it works.
    148   using Func = size_t (*)(size_t idx);
    149   Func fn = (Func)span.rx();
    150 
    151   printf("\n");
    152   if (fn(0) != data_array[0] ||
    153       fn(3) != data_array[3] ||
    154       fn(6) != data_array[6] ||
    155       fn(9) != data_array[9] ) {
    156     printf("** FAILURE: The generated function returned incorrect result(s) **\n");
    157     return 1;
    158   }
    159 
    160   printf("** SUCCESS **\n");
    161   return 0;
    162 }
    163 
    164 #else
    165 int main() {
    166   printf("!! This test is disabled: ASMJIT_NO_JIT or unsuitable target architecture !!\n\n");
    167   return 0;
    168 }
    169 #endif // ASMJIT_ARCH_X86 && !ASMJIT_NO_X86 && !ASMJIT_NO_JIT