Coverage Report

Created: 2025-11-24 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/llvm/codegen.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
4
#include "llvm/codegen.h"
5
6
#include "aot/version.h"
7
#include "common/defines.h"
8
#include "common/hash.h"
9
#include "data.h"
10
#include "llvm.h"
11
12
#include <charconv>
13
#include <fstream>
14
#include <lld/Common/Driver.h>
15
#include <random>
16
#include <sstream>
17
18
#if LLVM_VERSION_MAJOR >= 14
19
#include <lld/Common/CommonLinkerContext.h>
20
#endif
21
#if LLVM_VERSION_MAJOR >= 17
22
#if WASMEDGE_OS_MACOS
23
LLD_HAS_DRIVER(macho)
24
#elif WASMEDGE_OS_LINUX
25
LLD_HAS_DRIVER(elf)
26
#elif WASMEDGE_OS_WINDOWS
27
LLD_HAS_DRIVER(coff)
28
#endif
29
#endif
30
31
#if WASMEDGE_OS_MACOS
32
#include <sys/utsname.h>
33
#include <unistd.h>
34
#endif
35
#if WASMEDGE_OS_WINDOWS
36
#include <llvm/Object/COFF.h>
37
#endif
38
39
#if WASMEDGE_OS_LINUX
40
90.5k
#define SYMBOL(X) X
41
#elif WASMEDGE_OS_MACOS
42
#define SYMBOL(X) "_" X
43
#elif WASMEDGE_OS_WINDOWS
44
#define SYMBOL(X) X
45
#endif
46
47
namespace LLVM = WasmEdge::LLVM;
48
using namespace std::literals;
49
50
namespace {
51
52
using namespace WasmEdge;
53
54
#if WASMEDGE_OS_MACOS
55
// Get current OS version
56
std::string getOSVersion() noexcept {
57
  struct utsname Info;
58
  if (::uname(&Info)) {
59
    // default os version
60
    return "13.0.0"s;
61
  }
62
  std::string_view Release = Info.release;
63
  auto GetNum = [](std::string_view &String) noexcept {
64
    uint64_t Result = 0;
65
    while (!String.empty() && std::isdigit(String[0])) {
66
      Result = Result * 10 + (String[0] - '0');
67
      String = String.substr(1);
68
    }
69
    return Result;
70
  };
71
  auto SkipDot = [](std::string_view &String) noexcept {
72
    if (!String.empty() && String[0] == '.')
73
      String = String.substr(1);
74
  };
75
  uint64_t Major = GetNum(Release);
76
  SkipDot(Release);
77
  uint64_t Minor = GetNum(Release);
78
  SkipDot(Release);
79
  uint64_t Micro = GetNum(Release);
80
81
  if (Major == 0) {
82
    Major = 8;
83
  }
84
  if (Major <= 19) {
85
    Micro = 0;
86
    Minor = Major - 4;
87
    Major = 10;
88
  } else {
89
    Micro = 0;
90
    Minor = 0;
91
    Major = 11 + Major - 20;
92
  }
93
94
  return fmt::format("{}.{}.{}"sv, Major, Minor, Micro);
95
}
96
// Get current SDK version
97
std::string getSDKVersion() noexcept {
98
  // TODO: parse SDKSettings.json to get real version
99
  return "12.1"s;
100
}
101
// Get current SDK version in pair
102
std::pair<uint32_t, uint32_t> getSDKVersionPair() noexcept {
103
  // TODO: parse SDKSettings.json to get real version
104
  return {UINT32_C(12), UINT32_C(1)};
105
}
106
#endif
107
108
3.77M
Expect<void> WriteByte(std::ostream &OS, uint8_t Data) noexcept {
109
3.77M
  OS.put(static_cast<char>(Data));
110
3.77M
  return {};
111
3.77M
}
112
113
20.5k
Expect<void> WriteU32(std::ostream &OS, uint32_t Data) noexcept {
114
25.7k
  do {
115
25.7k
    uint8_t Byte = static_cast<uint8_t>(Data & UINT32_C(0x7f));
116
25.7k
    Data >>= 7;
117
25.7k
    if (Data > UINT32_C(0)) {
118
5.24k
      Byte |= UINT8_C(0x80);
119
5.24k
    }
120
25.7k
    WriteByte(OS, Byte);
121
25.7k
  } while (Data > UINT32_C(0));
122
20.5k
  return {};
123
20.5k
}
124
125
47.5k
Expect<void> WriteU64(std::ostream &OS, uint64_t Data) noexcept {
126
84.8k
  do {
127
84.8k
    uint8_t Byte = static_cast<uint8_t>(Data & UINT64_C(0x7f));
128
84.8k
    Data >>= 7;
129
84.8k
    if (Data > UINT64_C(0)) {
130
37.2k
      Byte |= UINT8_C(0x80);
131
37.2k
    }
132
84.8k
    WriteByte(OS, Byte);
133
84.8k
  } while (Data > UINT64_C(0));
134
47.5k
  return {};
135
47.5k
}
136
137
15.8k
Expect<void> WriteName(std::ostream &OS, std::string_view Data) noexcept {
138
15.8k
  WriteU32(OS, static_cast<uint32_t>(Data.size()));
139
3.64M
  for (const auto C : Data) {
140
3.64M
    WriteByte(OS, static_cast<uint8_t>(C));
141
3.64M
  }
142
15.8k
  return {};
143
15.8k
}
144
145
inline constexpr bool startsWith(std::string_view Value,
146
31.4k
                                 std::string_view Prefix) noexcept {
147
31.4k
  return Value.size() >= Prefix.size() &&
148
31.4k
         Value.substr(0, Prefix.size()) == Prefix;
149
31.4k
}
150
151
4.64k
std::filesystem::path uniquePath(const std::filesystem::path Model) noexcept {
152
4.64k
  using size_type = std::filesystem::path::string_type::size_type;
153
4.64k
  using value_type = std::filesystem::path::value_type;
154
4.64k
  static const auto Hex = "0123456789abcdef"sv;
155
4.64k
  std::uniform_int_distribution<size_type> Distribution(0, Hex.size() - 1);
156
4.64k
  auto String = Model.native();
157
134k
  for (size_type N = String.size(), I = 0; I < N; ++I) {
158
130k
    if (String[I] == static_cast<value_type>('%')) {
159
46.4k
      String[I] = static_cast<value_type>(Hex[Distribution(Hash::RandEngine)]);
160
46.4k
    }
161
130k
  }
162
4.64k
  return String;
163
4.64k
}
164
165
4.64k
std::filesystem::path createTemp(const std::filesystem::path Model) noexcept {
166
4.64k
  while (true) {
167
4.64k
    auto Result = uniquePath(Model);
168
4.64k
    std::error_code Error;
169
4.64k
    if (!std::filesystem::exists(Result, Error)) {
170
4.64k
      if (Error) {
171
0
        return {};
172
0
      }
173
4.64k
      return Result;
174
4.64k
    }
175
4.64k
  }
176
4.64k
}
177
178
// Write output object and link
179
Expect<void> outputNativeLibrary(const std::filesystem::path &OutputPath,
180
2.32k
                                 const LLVM::MemoryBuffer &OSVec) noexcept {
181
2.32k
  spdlog::info("output start"sv);
182
2.32k
  std::filesystem::path ObjectName;
183
2.32k
  {
184
    // tempfile
185
2.32k
    std::filesystem::path OPath(OutputPath);
186
#if WASMEDGE_OS_WINDOWS
187
    OPath.replace_extension("%%%%%%%%%%.obj"sv);
188
#else
189
2.32k
    OPath.replace_extension("%%%%%%%%%%.o"sv);
190
2.32k
#endif
191
2.32k
    ObjectName = createTemp(OPath);
192
2.32k
    if (ObjectName.empty()) {
193
      // TODO:return error
194
0
      spdlog::error("so file creation failed:{}"sv, OPath.u8string());
195
0
      return Unexpect(ErrCode::Value::IllegalPath);
196
0
    }
197
2.32k
    std::ofstream OS(ObjectName, std::ios_base::binary);
198
2.32k
    OS.write(OSVec.data(), static_cast<std::streamsize>(OSVec.size()));
199
2.32k
    OS.close();
200
2.32k
  }
201
202
  // link
203
0
  bool LinkResult = false;
204
#if WASMEDGE_OS_MACOS
205
  const auto OSVersion = getOSVersion();
206
  const auto SDKVersion = getSDKVersion();
207
#if LLVM_VERSION_MAJOR >= 14
208
  // LLVM 14 replaces the older mach_o lld implementation with the new one.
209
  // So we need to change the namespace after LLVM 14.x released.
210
  // Reference: https://reviews.llvm.org/D114842
211
  LinkResult = lld::macho::link(
212
#else
213
  LinkResult = lld::mach_o::link(
214
#endif
215
      std::initializer_list<const char *>{
216
          "lld", "-arch",
217
#if defined(__x86_64__)
218
          "x86_64",
219
#elif defined(__aarch64__)
220
          "arm64",
221
#else
222
#error Unsupported architecture on the MacOS!
223
#endif
224
#if LLVM_VERSION_MAJOR >= 14
225
          // LLVM 14 replaces the older mach_o lld implementation with the new
226
          // one. And it require -arch and -platform_version to always be
227
          // specified. Reference: https://reviews.llvm.org/D97799
228
          "-platform_version", "macos", OSVersion.c_str(), SDKVersion.c_str(),
229
#else
230
          "-sdk_version", SDKVersion.c_str(),
231
#endif
232
          "-dylib", "-demangle", "-macosx_version_min", OSVersion.c_str(),
233
          "-syslibroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk",
234
          ObjectName.u8string().c_str(), "-o", OutputPath.u8string().c_str()},
235
#elif WASMEDGE_OS_LINUX
236
  LinkResult = lld::elf::link(
237
2.32k
      std::initializer_list<const char *>{"ld.lld", "--eh-frame-hdr",
238
2.32k
                                          "--shared", "--gc-sections",
239
2.32k
                                          "--discard-all", ObjectName.c_str(),
240
2.32k
                                          "-o", OutputPath.u8string().c_str()},
241
#elif WASMEDGE_OS_WINDOWS
242
  LinkResult = lld::coff::link(
243
      std::initializer_list<const char *>{
244
          "lld-link", "-dll", "-base:0", "-nologo",
245
          ObjectName.u8string().c_str(),
246
          ("-out:" + OutputPath.u8string()).c_str()},
247
#endif
248
249
#if LLVM_VERSION_MAJOR >= 14
250
      llvm::outs(), llvm::errs(), false, false
251
#elif LLVM_VERSION_MAJOR >= 10
252
      false, llvm::outs(), llvm::errs()
253
#else
254
      false, llvm::errs()
255
#endif
256
2.32k
  );
257
258
#if LLVM_VERSION_MAJOR >= 14
259
  lld::CommonLinkerContext::destroy();
260
#endif
261
262
2.32k
  if (LinkResult) {
263
2.32k
    std::error_code Error;
264
2.32k
    std::filesystem::remove(ObjectName, Error);
265
#if WASMEDGE_OS_WINDOWS
266
    std::filesystem::path LibPath(OutputPath);
267
    LibPath.replace_extension(".lib"sv);
268
    std::filesystem::remove(LibPath, Error);
269
#endif
270
271
2.32k
    spdlog::info("codegen done"sv);
272
2.32k
  } else {
273
0
    spdlog::error("link error"sv);
274
0
  }
275
276
#if WASMEDGE_OS_MACOS
277
  // codesign
278
  if (LinkResult) {
279
    pid_t PID = ::fork();
280
    if (PID == -1) {
281
      spdlog::error("codesign error on fork:{}"sv, std::strerror(errno));
282
    } else if (PID == 0) {
283
      execlp("/usr/bin/codesign", "codesign", "-s", "-",
284
             OutputPath.u8string().c_str(), nullptr);
285
      std::exit(256);
286
    } else {
287
      int ChildStat;
288
      waitpid(PID, &ChildStat, 0);
289
      if (const int Status = WEXITSTATUS(ChildStat); Status != 0) {
290
        spdlog::error("codesign exited with status {}"sv, Status);
291
      }
292
    }
293
  }
294
#endif
295
296
2.32k
  return {};
297
2.32k
}
298
299
Expect<void> outputWasmLibrary(LLVM::Context LLContext,
300
                               const std::filesystem::path &OutputPath,
301
                               Span<const Byte> Data,
302
2.32k
                               const LLVM::MemoryBuffer &OSVec) noexcept {
303
2.32k
  std::filesystem::path SharedObjectName;
304
2.32k
  {
305
    // tempfile
306
2.32k
    std::filesystem::path SOPath(OutputPath);
307
2.32k
    SOPath.replace_extension("%%%%%%%%%%" WASMEDGE_LIB_EXTENSION);
308
2.32k
    SharedObjectName = createTemp(SOPath);
309
2.32k
    if (SharedObjectName.empty()) {
310
      // TODO:return error
311
0
      spdlog::error("so file creation failed:{}"sv, SOPath.u8string());
312
0
      return Unexpect(ErrCode::Value::IllegalPath);
313
0
    }
314
2.32k
    std::ofstream OS(SharedObjectName, std::ios_base::binary);
315
2.32k
    OS.write(OSVec.data(), static_cast<std::streamsize>(OSVec.size()));
316
2.32k
    OS.close();
317
2.32k
  }
318
319
2.32k
  EXPECTED_TRY(outputNativeLibrary(SharedObjectName, OSVec));
320
321
2.32k
  LLVM::MemoryBuffer SOFile;
322
2.32k
  if (auto [Res, ErrorMessage] =
323
2.32k
          LLVM::MemoryBuffer::getFile(SharedObjectName.u8string().c_str());
324
2.32k
      unlikely(ErrorMessage)) {
325
0
    spdlog::error("object file open error:{}"sv, ErrorMessage.string_view());
326
0
    return Unexpect(ErrCode::Value::IllegalPath);
327
2.32k
  } else {
328
2.32k
    SOFile = std::move(Res);
329
2.32k
  }
330
331
2.32k
  LLVM::Binary ObjFile;
332
2.32k
  if (auto [Res, ErrorMessage] = LLVM::Binary::create(SOFile, LLContext);
333
2.32k
      unlikely(ErrorMessage)) {
334
0
    spdlog::error("object file parse error:{}"sv, ErrorMessage.string_view());
335
0
    return Unexpect(ErrCode::Value::IllegalPath);
336
2.32k
  } else {
337
2.32k
    ObjFile = std::move(Res);
338
2.32k
  }
339
340
2.32k
  std::string OSCustomSecVec;
341
2.32k
  {
342
2.32k
    std::ostringstream OS;
343
2.32k
    WriteName(OS, "wasmedge"sv);
344
2.32k
    WriteU32(OS, AOT::kBinaryVersion);
345
346
2.32k
#if WASMEDGE_OS_LINUX
347
2.32k
    WriteByte(OS, UINT8_C(1));
348
#elif WASMEDGE_OS_MACOS
349
    WriteByte(OS, UINT8_C(2));
350
#elif WASMEDGE_OS_WINDOWS
351
    WriteByte(OS, UINT8_C(3));
352
#else
353
#error Unsupported operating system!
354
#endif
355
356
2.32k
#if defined(__x86_64__)
357
2.32k
    WriteByte(OS, UINT8_C(1));
358
#elif defined(__aarch64__)
359
    WriteByte(OS, UINT8_C(2));
360
#elif defined(__riscv) && __riscv_xlen == 64
361
    WriteByte(OS, UINT8_C(3));
362
#elif defined(__arm__) && __ARM_ARCH == 7
363
    WriteByte(OS, UINT8_C(4));
364
#elif defined(__s390x__)
365
    WriteByte(OS, UINT8_C(5));
366
#else
367
#error Unsupported hardware architecture!
368
#endif
369
370
2.32k
    std::vector<std::pair<std::string, uint64_t>> SymbolTable;
371
2.32k
#if !WASMEDGE_OS_WINDOWS
372
2.32k
    for (auto Symbol = ObjFile.symbols();
373
25.1k
         Symbol && !ObjFile.isSymbolEnd(Symbol); Symbol.next()) {
374
22.8k
      SymbolTable.emplace_back(Symbol.getName(), Symbol.getAddress());
375
22.8k
    }
376
#else
377
    for (auto &Symbol :
378
         llvm::object::unwrap<llvm::object::COFFObjectFile>(ObjFile.unwrap())
379
             ->export_directories()) {
380
      llvm::StringRef Name;
381
      if (auto Error = Symbol.getSymbolName(Name); unlikely(!!Error)) {
382
        continue;
383
      } else if (Name.empty()) {
384
        continue;
385
      }
386
      uint32_t Offset = 0;
387
      if (auto Error = Symbol.getExportRVA(Offset); unlikely(!!Error)) {
388
        continue;
389
      }
390
      SymbolTable.emplace_back(Name.str(), Offset);
391
    }
392
#endif
393
2.32k
    uint64_t VersionAddress = 0, IntrinsicsAddress = 0;
394
2.32k
    std::vector<uint64_t> Types;
395
2.32k
    std::vector<uint64_t> Codes;
396
2.32k
    uint64_t CodesMin = std::numeric_limits<uint64_t>::max();
397
22.8k
    for (const auto &[Name, Address] : SymbolTable) {
398
22.8k
      if (Name == SYMBOL("version"sv)) {
399
2.32k
        VersionAddress = Address;
400
20.4k
      } else if (Name == SYMBOL("intrinsics"sv)) {
401
2.32k
        IntrinsicsAddress = Address;
402
18.1k
      } else if (startsWith(Name, SYMBOL("t"sv))) {
403
4.84k
        uint64_t Index = 0;
404
4.84k
        std::from_chars(Name.data() + SYMBOL("t"sv).size(),
405
4.84k
                        Name.data() + Name.size(), Index);
406
4.84k
        if (Types.size() < Index + 1) {
407
4.41k
          Types.resize(Index + 1);
408
4.41k
        }
409
4.84k
        Types[Index] = Address;
410
13.3k
      } else if (startsWith(Name, SYMBOL("f"sv))) {
411
10.9k
        uint64_t Index = 0;
412
10.9k
        std::from_chars(Name.data() + SYMBOL("f"sv).size(),
413
10.9k
                        Name.data() + Name.size(), Index);
414
10.9k
        if (Codes.size() < Index + 1) {
415
9.08k
          Codes.resize(Index + 1);
416
9.08k
        }
417
10.9k
        CodesMin = std::min(CodesMin, Index);
418
10.9k
        Codes[Index] = Address;
419
10.9k
      }
420
22.8k
    }
421
2.32k
    if (CodesMin != std::numeric_limits<uint64_t>::max()) {
422
2.09k
      Codes.erase(Codes.begin(),
423
2.09k
                  Codes.begin() + static_cast<int64_t>(CodesMin));
424
2.09k
    }
425
2.32k
    WriteU64(OS, VersionAddress);
426
2.32k
    WriteU64(OS, IntrinsicsAddress);
427
2.32k
    WriteU64(OS, Types.size());
428
4.84k
    for (const uint64_t TypeAddress : Types) {
429
4.84k
      WriteU64(OS, TypeAddress);
430
4.84k
    }
431
2.32k
    WriteU64(OS, Codes.size());
432
10.9k
    for (const uint64_t CodeAddress : Codes) {
433
10.9k
      WriteU64(OS, CodeAddress);
434
10.9k
    }
435
436
2.32k
    uint32_t SectionCount = 0;
437
36.7k
    for (auto Section = ObjFile.sections(); !ObjFile.isSectionEnd(Section);
438
34.4k
         Section.next()) {
439
34.4k
      if (Section.getSize() == 0) {
440
2.32k
        continue;
441
2.32k
      }
442
32.1k
      if (!Section.isEHFrame() && !Section.isPData() && !Section.isText() &&
443
27.7k
          !Section.isData() && !Section.isBSS()) {
444
20.9k
        continue;
445
20.9k
      }
446
11.2k
      ++SectionCount;
447
11.2k
    }
448
2.32k
    WriteU32(OS, SectionCount);
449
450
36.7k
    for (auto Section = ObjFile.sections(); !ObjFile.isSectionEnd(Section);
451
34.4k
         Section.next()) {
452
34.4k
      if (Section.getSize() == 0) {
453
2.32k
        continue;
454
2.32k
      }
455
32.1k
      std::vector<char> Content(Section.getSize());
456
32.1k
      if (!Section.isVirtual()) {
457
29.8k
        if (auto Res = Section.getContents(); unlikely(Res.empty())) {
458
0
          assumingUnreachable();
459
29.8k
        } else {
460
29.8k
          Content.assign(Res.begin(), Res.end());
461
29.8k
        }
462
29.8k
      }
463
32.1k
      if (Section.isEHFrame() || Section.isPData()) {
464
2.19k
        WriteByte(OS, UINT8_C(4));
465
29.9k
      } else if (Section.isText()) {
466
2.19k
        WriteByte(OS, UINT8_C(1));
467
27.7k
      } else if (Section.isData()) {
468
4.51k
        WriteByte(OS, UINT8_C(2));
469
23.2k
      } else if (Section.isBSS()) {
470
2.32k
        WriteByte(OS, UINT8_C(3));
471
20.9k
      } else {
472
20.9k
        continue;
473
20.9k
      }
474
475
11.2k
      WriteU64(OS, Section.getAddress());
476
11.2k
      WriteU64(OS, Content.size());
477
11.2k
      WriteName(OS, std::string_view(Content.data(), Content.size()));
478
11.2k
    }
479
2.32k
    OSCustomSecVec = OS.str();
480
2.32k
  }
481
482
0
  spdlog::info("output start"sv);
483
484
2.32k
  std::ofstream OS(OutputPath, std::ios_base::binary);
485
2.32k
  if (!OS) {
486
0
    spdlog::error("output failed."sv);
487
0
    return Unexpect(ErrCode::Value::IllegalPath);
488
0
  }
489
2.32k
  OS.write(reinterpret_cast<const char *>(Data.data()),
490
2.32k
           static_cast<std::streamsize>(Data.size()));
491
  // Custom section id
492
2.32k
  WriteByte(OS, UINT8_C(0x00));
493
2.32k
  WriteName(OS, std::string_view(OSCustomSecVec.data(), OSCustomSecVec.size()));
494
495
2.32k
  std::error_code Error;
496
2.32k
  std::filesystem::remove(SharedObjectName, Error);
497
498
2.32k
  spdlog::info("output done"sv);
499
2.32k
  return {};
500
2.32k
}
501
502
} // namespace
503
504
namespace WasmEdge::LLVM {
505
506
Expect<void> CodeGen::codegen(Span<const Byte> WasmData, Data D,
507
2.32k
                              std::filesystem::path OutputPath) noexcept {
508
2.32k
  auto LLContext = D.extract().getLLContext();
509
2.32k
  auto &LLModule = D.extract().LLModule;
510
2.32k
  auto &TM = D.extract().TM;
511
2.32k
  std::filesystem::path LLPath(OutputPath);
512
2.32k
  LLPath.replace_extension("ll"sv);
513
514
#if WASMEDGE_OS_WINDOWS
515
  {
516
    // create dummy dllmain function
517
    auto FTy = LLVM::Type::getFunctionType(LLContext.getInt32Ty(), {});
518
    auto F =
519
        LLModule.addFunction(FTy, LLVMExternalLinkage, "_DllMainCRTStartup");
520
    F.setVisibility(LLVMProtectedVisibility);
521
    F.setDSOLocal(true);
522
    F.addFnAttr(
523
        LLVM::Attribute::createString(LLContext, "no-stack-arg-probe"sv, {}));
524
    F.addFnAttr(
525
        LLVM::Attribute::createEnum(LLContext, LLVM::Core::StrictFP, 0));
526
    F.addFnAttr(LLVM::Attribute::createEnum(LLContext, LLVM::Core::UWTable,
527
                                            LLVM::Core::UWTableDefault));
528
    F.addFnAttr(
529
        LLVM::Attribute::createEnum(LLContext, LLVM::Core::NoReturn, 0));
530
    LLVM::Builder Builder(LLContext);
531
    Builder.positionAtEnd(LLVM::BasicBlock::create(LLContext, F, "entry"));
532
    Builder.createRet(LLContext.getInt32(1u));
533
534
    auto A = LLModule.addAlias(F.getType(), F, "_fltused");
535
    A.setLinkage(LLVMExternalLinkage);
536
    A.setVisibility(LLVMProtectedVisibility);
537
    A.setDSOLocal(true);
538
  }
539
#endif
540
#if WASMEDGE_OS_MACOS
541
  {
542
    const auto [Major, Minor] = getSDKVersionPair();
543
    LLModule.addFlag(LLVMModuleFlagBehaviorError, "SDK Version"sv,
544
                     LLVM::Value::getConstVector32(LLContext, {Major, Minor}));
545
  }
546
#endif
547
548
2.32k
  if (Conf.getCompilerConfigure().getOutputFormat() !=
549
2.32k
      CompilerConfigure::OutputFormat::Wasm) {
550
    // create wasm.code and wasm.size
551
0
    auto Int32Ty = LLContext.getInt32Ty();
552
0
    auto Content = LLVM::Value::getConstString(
553
0
        LLContext,
554
0
        {reinterpret_cast<const char *>(WasmData.data()), WasmData.size()},
555
0
        true);
556
0
    LLModule.addGlobal(Content.getType(), true, LLVMExternalLinkage, Content,
557
0
                       "wasm.code");
558
0
    LLModule.addGlobal(Int32Ty, true, LLVMExternalLinkage,
559
0
                       LLVM::Value::getConstInt(Int32Ty, WasmData.size()),
560
0
                       "wasm.size");
561
0
    for (auto Fn = LLModule.getFirstFunction(); Fn; Fn = Fn.getNextFunction()) {
562
0
      if (Fn.getLinkage() == LLVMInternalLinkage) {
563
0
        Fn.setLinkage(LLVMExternalLinkage);
564
0
        Fn.setVisibility(LLVMProtectedVisibility);
565
0
        Fn.setDSOLocal(true);
566
0
        Fn.setDLLStorageClass(LLVMDLLExportStorageClass);
567
0
      }
568
0
    }
569
2.32k
  } else {
570
20.2k
    for (auto Fn = LLModule.getFirstFunction(); Fn; Fn = Fn.getNextFunction()) {
571
17.9k
      if (Fn.getLinkage() == LLVMInternalLinkage) {
572
39
        Fn.setLinkage(LLVMPrivateLinkage);
573
39
        Fn.setDSOLocal(true);
574
39
        Fn.setDLLStorageClass(LLVMDefaultStorageClass);
575
39
      }
576
17.9k
    }
577
2.32k
  }
578
579
  // set dllexport
580
6.98k
  for (auto GV = LLModule.getFirstGlobal(); GV; GV = GV.getNextGlobal()) {
581
4.65k
    if (GV.getLinkage() == LLVMExternalLinkage) {
582
4.64k
      GV.setVisibility(LLVMProtectedVisibility);
583
4.64k
      GV.setDSOLocal(true);
584
4.64k
      GV.setDLLStorageClass(LLVMDLLExportStorageClass);
585
4.64k
    }
586
4.65k
  }
587
588
2.32k
  if (Conf.getCompilerConfigure().isDumpIR()) {
589
0
    if (auto ErrorMessage = LLModule.printModuleToFile("wasm.ll");
590
0
        unlikely(ErrorMessage)) {
591
0
      spdlog::error("wasm.ll open error:{}"sv, ErrorMessage.string_view());
592
0
      return WasmEdge::Unexpect(WasmEdge::ErrCode::Value::IllegalPath);
593
0
    }
594
0
  }
595
596
2.32k
  spdlog::info("codegen start"sv);
597
  // codegen
598
2.32k
  {
599
2.32k
    if (Conf.getCompilerConfigure().isDumpIR()) {
600
0
      if (auto ErrorMessage = LLModule.printModuleToFile("wasm-opt.ll")) {
601
        // TODO:return error
602
0
        spdlog::error("printModuleToFile failed"sv);
603
0
        return Unexpect(ErrCode::Value::IllegalPath);
604
0
      }
605
0
    }
606
607
2.32k
    auto [OSVec, ErrorMessage] =
608
2.32k
        TM.emitToMemoryBuffer(LLModule, LLVMObjectFile);
609
2.32k
    if (ErrorMessage) {
610
      // TODO:return error
611
0
      spdlog::error("addPassesToEmitFile failed"sv);
612
0
      return Unexpect(ErrCode::Value::IllegalPath);
613
0
    }
614
615
2.32k
    if (Conf.getCompilerConfigure().getOutputFormat() ==
616
2.32k
        CompilerConfigure::OutputFormat::Wasm) {
617
2.32k
      EXPECTED_TRY(outputWasmLibrary(LLContext, OutputPath, WasmData, OSVec));
618
2.32k
    } else {
619
0
      EXPECTED_TRY(outputNativeLibrary(OutputPath, OSVec));
620
0
    }
621
2.32k
  }
622
623
2.32k
  return {};
624
2.32k
}
625
626
} // namespace WasmEdge::LLVM