Coverage Report

Created: 2025-07-01 06:18

/src/WasmEdge/lib/loader/aot_section.cpp
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
4
#include "loader/aot_section.h"
5
#include "common/spdlog.h"
6
#include "system/allocator.h"
7
8
#if WASMEDGE_OS_LINUX || WASMEDGE_OS_MACOS
9
extern "C" {
10
extern void __register_frame(void *);
11
extern void __deregister_frame(void *);
12
}
13
#endif
14
15
using namespace std::literals;
16
17
namespace {
18
0
inline constexpr uint64_t roundDownPageBoundary(const uint64_t Value) {
19
// ARM64 Mac has a special page size
20
#if WASMEDGE_OS_MACOS && defined(__aarch64__)
21
  return Value & ~UINT64_C(16383);
22
#else
23
0
  return Value & ~UINT64_C(4095);
24
0
#endif
25
0
}
26
0
inline constexpr uint64_t roundUpPageBoundary(const uint64_t Value) {
27
// ARM64 Mac has a special page size
28
#if WASMEDGE_OS_MACOS && defined(__aarch64__)
29
  return roundDownPageBoundary(Value + UINT64_C(16383));
30
#else
31
0
  return roundDownPageBoundary(Value + UINT64_C(4095));
32
0
#endif
33
0
}
34
} // namespace
35
36
namespace WasmEdge::Loader {
37
38
0
Expect<void> AOTSection::load(const AST::AOTSection &AOTSec) noexcept {
39
0
  BinarySize = 0;
40
0
  for (const auto &Section : AOTSec.getSections()) {
41
0
    const auto Offset = std::get<1>(Section);
42
0
    const auto Size = std::get<2>(Section);
43
0
    BinarySize = std::max(BinarySize, Offset + Size);
44
0
  }
45
0
  BinarySize = roundUpPageBoundary(BinarySize);
46
47
0
  Binary = Allocator::allocate_chunk(BinarySize);
48
0
  if (unlikely(!Binary)) {
49
0
    spdlog::error(ErrCode::Value::MemoryOutOfBounds);
50
0
    return Unexpect(ErrCode::Value::MemoryOutOfBounds);
51
0
  }
52
53
0
  std::vector<std::pair<uint8_t *, uint64_t>> ExecutableRanges;
54
0
  for (const auto &Section : AOTSec.getSections()) {
55
0
    const auto Offset = std::get<1>(Section);
56
0
    const auto Size = std::get<2>(Section);
57
0
    const auto &Content = std::get<3>(Section);
58
0
    if (Size > BinarySize || Offset > BinarySize ||
59
0
        Offset + Size > BinarySize || Content.size() > Size) {
60
0
      return Unexpect(ErrCode::Value::IntegerTooLarge);
61
0
    }
62
0
    std::copy(Content.begin(), Content.end(), Binary + Offset);
63
0
    switch (std::get<0>(Section)) {
64
0
    case 1: { // Text
65
0
      const auto O = roundDownPageBoundary(Offset);
66
0
      const auto S = roundUpPageBoundary(Size + (Offset - O));
67
0
      ExecutableRanges.emplace_back(Binary + O, S);
68
0
      break;
69
0
    }
70
0
    case 2: // Data
71
0
      break;
72
0
    case 3: // BSS
73
0
      break;
74
0
#if WASMEDGE_OS_LINUX
75
0
    case 4: // EHFrame
76
0
      EHFrameAddress = reinterpret_cast<void *>(Binary + Offset);
77
0
      break;
78
#elif WASMEDGE_OS_MACOS
79
    case 4: // EHFrame
80
      EHFrameAddress = reinterpret_cast<uint8_t *>(Binary + Offset);
81
      EHFrameSize = Size;
82
      break;
83
#elif WASMEDGE_OS_WINDOWS
84
    case 4: // PData
85
      PDataAddress = reinterpret_cast<void *>(Binary + Offset);
86
      PDataSize =
87
          static_cast<uint32_t>(Size / sizeof(winapi::RUNTIME_FUNCTION_));
88
      break;
89
#endif
90
0
    default:
91
0
      return Unexpect(ErrCode::Value::IntegerTooLarge);
92
0
    }
93
0
  }
94
95
0
  for (const auto &[Pointer, Size] : ExecutableRanges) {
96
0
    if (!Allocator::set_chunk_executable(Pointer, Size)) {
97
0
      spdlog::error(ErrCode::Value::MemoryOutOfBounds);
98
0
      spdlog::error("    set_chunk_executable failed:{}"sv,
99
0
                    std::strerror(errno));
100
0
      return Unexpect(ErrCode::Value::MemoryOutOfBounds);
101
0
    }
102
0
  }
103
104
0
  IntrinsicsAddress = AOTSec.getIntrinsicsAddress();
105
0
  TypesAddress = AOTSec.getTypesAddress();
106
0
  CodesAddress = AOTSec.getCodesAddress();
107
108
0
#if WASMEDGE_OS_LINUX
109
0
  if (EHFrameAddress) {
110
0
    __register_frame(EHFrameAddress);
111
0
  }
112
#elif WASMEDGE_OS_MACOS
113
  if (EHFrameAddress) {
114
    auto Iter = EHFrameAddress;
115
    const auto End = EHFrameAddress + EHFrameSize - 4;
116
117
    while (Iter < End) {
118
      if (Iter != EHFrameAddress) {
119
        __register_frame(Iter);
120
      }
121
      const uint32_t Length = *reinterpret_cast<const uint32_t *>(Iter);
122
      Iter += Length + 4;
123
    }
124
  }
125
#elif WASMEDGE_OS_WINDOWS
126
  if (PDataSize != 0) {
127
    winapi::RtlAddFunctionTable(
128
        static_cast<winapi::PRUNTIME_FUNCTION_>(PDataAddress), PDataSize,
129
        reinterpret_cast<winapi::ULONG_PTR_>(Binary));
130
  }
131
#endif
132
133
0
  return {};
134
0
}
135
136
0
void AOTSection::unload() noexcept {
137
0
  if (Binary) {
138
0
#if WASMEDGE_OS_LINUX
139
0
    if (EHFrameAddress) {
140
0
      __deregister_frame(EHFrameAddress);
141
0
    }
142
#elif WASMEDGE_OS_MACOS
143
    if (EHFrameAddress) {
144
      auto Iter = EHFrameAddress;
145
      const auto End = EHFrameAddress + EHFrameSize - 4;
146
147
      while (Iter < End) {
148
        if (Iter != EHFrameAddress) {
149
          __deregister_frame(Iter);
150
        }
151
        const uint32_t Length = *reinterpret_cast<const uint32_t *>(Iter);
152
        Iter += Length + 4;
153
      }
154
    }
155
#elif WASMEDGE_OS_WINDOWS
156
    if (PDataSize != 0) {
157
      winapi::RtlDeleteFunctionTable(
158
          static_cast<winapi::PRUNTIME_FUNCTION_>(PDataAddress));
159
    }
160
#endif
161
0
    Allocator::set_chunk_readable_writable(Binary, BinarySize);
162
0
    Allocator::release_chunk(Binary, BinarySize);
163
0
    Binary = nullptr;
164
0
  }
165
0
}
166
167
} // namespace WasmEdge::Loader