mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
remove all IBM AIX and z/OS support
As with Solaris (dba1bf9353), we have no way to
actually audit contributions for these OSs. IBM also makes it even harder than
Oracle to actually obtain these OSs.
closes #23695
closes #23694
closes #3655
closes #23693
This commit is contained in:
parent
6568f0f75b
commit
a7119d4269
38 changed files with 47 additions and 1910 deletions
|
|
@ -581,7 +581,6 @@ set(ZIG_STAGE2_SOURCES
|
|||
src/link/Elf/relocation.zig
|
||||
src/link/Elf/synthetic_sections.zig
|
||||
src/link/Elf2.zig
|
||||
src/link/Goff.zig
|
||||
src/link/LdScript.zig
|
||||
src/link/Lld.zig
|
||||
src/link/MachO.zig
|
||||
|
|
@ -617,7 +616,6 @@ set(ZIG_STAGE2_SOURCES
|
|||
src/link/Wasm/Archive.zig
|
||||
src/link/Wasm/Flush.zig
|
||||
src/link/Wasm/Object.zig
|
||||
src/link/Xcoff.zig
|
||||
src/link/aarch64.zig
|
||||
src/link/riscv.zig
|
||||
src/link/table_section.zig
|
||||
|
|
|
|||
8
lib/compiler/aro/aro/Compilation.zig
vendored
8
lib/compiler/aro/aro/Compilation.zig
vendored
|
|
@ -362,7 +362,6 @@ fn generateSystemDefines(comp: *Compilation, w: *std.Io.Writer) !void {
|
|||
.haiku,
|
||||
.hurd,
|
||||
.illumos,
|
||||
.aix,
|
||||
.emscripten,
|
||||
.ps4,
|
||||
.ps5,
|
||||
|
|
@ -1006,13 +1005,6 @@ fn writeBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefinesMode
|
|||
\\
|
||||
);
|
||||
},
|
||||
.aix => {
|
||||
try w.writeAll(
|
||||
\\#define __STDC_NO_THREADS__ 1
|
||||
\\#define __STDC_NO_ATOMICS__ 1
|
||||
\\
|
||||
);
|
||||
},
|
||||
else => {},
|
||||
};
|
||||
if (comp.langopts.standard.StdCVersionMacro()) |stdc_version| {
|
||||
|
|
|
|||
2
lib/compiler/aro/aro/Driver.zig
vendored
2
lib/compiler/aro/aro/Driver.zig
vendored
|
|
@ -810,7 +810,7 @@ pub fn parseArgs(
|
|||
if (strip) break :debug .strip;
|
||||
if (debug) |explicit| break :debug explicit;
|
||||
break :debug switch (d.comp.target.ofmt) {
|
||||
.elf, .goff, .macho, .wasm, .xcoff => .{ .dwarf = .@"32" },
|
||||
.elf, .macho, .wasm => .{ .dwarf = .@"32" },
|
||||
.coff => .code_view,
|
||||
.c => switch (d.comp.target.os.tag) {
|
||||
.windows, .uefi => .code_view,
|
||||
|
|
|
|||
10
lib/compiler/aro/aro/Toolchain.zig
vendored
10
lib/compiler/aro/aro/Toolchain.zig
vendored
|
|
@ -369,7 +369,7 @@ fn getUnwindLibKind(tc: *const Toolchain) !UnwindLibKind {
|
|||
switch (tc.getRuntimeLibKind()) {
|
||||
.compiler_rt => {
|
||||
const target = tc.getTarget();
|
||||
if (target.abi.isAndroid() or target.os.tag == .aix) {
|
||||
if (target.abi.isAndroid()) {
|
||||
return .compiler_rt;
|
||||
} else {
|
||||
return .none;
|
||||
|
|
@ -408,7 +408,7 @@ fn addUnwindLibrary(tc: *const Toolchain, argv: *std.ArrayList([]const u8)) !voi
|
|||
unw == .none) return;
|
||||
|
||||
const lgk = tc.getLibGCCKind();
|
||||
const as_needed = lgk == .unspecified and !target.abi.isAndroid() and !target_util.isCygwinMinGW(target) and target.os.tag != .aix;
|
||||
const as_needed = lgk == .unspecified and !target.abi.isAndroid() and !target_util.isCygwinMinGW(target);
|
||||
|
||||
try argv.ensureUnusedCapacity(tc.driver.comp.gpa, 3);
|
||||
if (as_needed) {
|
||||
|
|
@ -417,11 +417,7 @@ fn addUnwindLibrary(tc: *const Toolchain, argv: *std.ArrayList([]const u8)) !voi
|
|||
switch (unw) {
|
||||
.none => return,
|
||||
.libgcc => argv.appendAssumeCapacity(if (lgk == .static) "-lgcc_eh" else "-lgcc_s"),
|
||||
.compiler_rt => if (target.os.tag == .aix) {
|
||||
if (lgk != .static) {
|
||||
argv.appendAssumeCapacity("-lunwind");
|
||||
}
|
||||
} else if (lgk == .static) {
|
||||
.compiler_rt => if (lgk == .static) {
|
||||
argv.appendAssumeCapacity("-l:libunwind.a");
|
||||
} else if (lgk == .shared) {
|
||||
if (target_util.isCygwinMinGW(target)) {
|
||||
|
|
|
|||
5
lib/compiler/aro/aro/TypeStore.zig
vendored
5
lib/compiler/aro/aro/TypeStore.zig
vendored
|
|
@ -2099,10 +2099,7 @@ fn generateVaListType(ts: *TypeStore, comp: *Compilation) !QualType {
|
|||
.hexagon_va_list
|
||||
else
|
||||
return .char_pointer,
|
||||
.powerpc, .powerpcle => switch (comp.target.os.tag) {
|
||||
.aix => return .char_pointer,
|
||||
else => .powerpc_va_list,
|
||||
},
|
||||
.powerpc, .powerpcle => .powerpc_va_list,
|
||||
.s390x => .s390x_va_list,
|
||||
.x86_64 => switch (comp.target.os.tag) {
|
||||
.uefi, .windows => return .char_pointer,
|
||||
|
|
|
|||
10
lib/compiler/aro/aro/target.zig
vendored
10
lib/compiler/aro/aro/target.zig
vendored
|
|
@ -403,7 +403,6 @@ pub fn builtinEnabled(target: std.Target, enabled_for: TargetSet) bool {
|
|||
}
|
||||
|
||||
pub fn defaultFpEvalMethod(target: std.Target) LangOpts.FPEvalMethod {
|
||||
if (target.os.tag == .aix) return .double;
|
||||
switch (target.cpu.arch) {
|
||||
.x86, .x86_64 => {
|
||||
if (target.ptrBitWidth() == 32 and target.os.tag == .netbsd) {
|
||||
|
|
@ -656,10 +655,8 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
|
|||
.openbsd => "openbsd",
|
||||
.illumos => "solaris",
|
||||
.windows => "windows",
|
||||
.zos => "zos",
|
||||
.haiku => "haiku",
|
||||
.rtems => "rtems",
|
||||
.aix => "aix",
|
||||
.cuda => "cuda",
|
||||
.nvcl => "nvcl",
|
||||
.amdhsa => "amdhsa",
|
||||
|
|
@ -741,7 +738,6 @@ pub const DefaultPIStatus = enum { yes, no, depends_on_linker };
|
|||
|
||||
pub fn isPIEDefault(target: std.Target) DefaultPIStatus {
|
||||
return switch (target.os.tag) {
|
||||
.aix,
|
||||
.haiku,
|
||||
|
||||
.macos,
|
||||
|
|
@ -765,7 +761,6 @@ pub fn isPIEDefault(target: std.Target) DefaultPIStatus {
|
|||
.ps5,
|
||||
|
||||
.hurd,
|
||||
.zos,
|
||||
=> .no,
|
||||
|
||||
.openbsd,
|
||||
|
|
@ -810,7 +805,6 @@ pub fn isPIEDefault(target: std.Target) DefaultPIStatus {
|
|||
|
||||
pub fn isPICdefault(target: std.Target) DefaultPIStatus {
|
||||
return switch (target.os.tag) {
|
||||
.aix,
|
||||
.haiku,
|
||||
|
||||
.macos,
|
||||
|
|
@ -830,7 +824,6 @@ pub fn isPICdefault(target: std.Target) DefaultPIStatus {
|
|||
|
||||
.fuchsia,
|
||||
.cuda,
|
||||
.zos,
|
||||
=> .no,
|
||||
|
||||
.dragonfly,
|
||||
|
|
@ -889,7 +882,7 @@ pub fn isPICdefault(target: std.Target) DefaultPIStatus {
|
|||
|
||||
pub fn isPICDefaultForced(target: std.Target) DefaultPIStatus {
|
||||
return switch (target.os.tag) {
|
||||
.aix, .amdhsa, .amdpal, .mesa3d => .yes,
|
||||
.amdhsa, .amdpal, .mesa3d => .yes,
|
||||
|
||||
.haiku,
|
||||
.dragonfly,
|
||||
|
|
@ -903,7 +896,6 @@ pub fn isPICDefaultForced(target: std.Target) DefaultPIStatus {
|
|||
.hurd,
|
||||
.linux,
|
||||
.fuchsia,
|
||||
.zos,
|
||||
=> .no,
|
||||
|
||||
.windows => {
|
||||
|
|
|
|||
18
lib/include/zos_wrappers/builtins.h
vendored
18
lib/include/zos_wrappers/builtins.h
vendored
|
|
@ -1,18 +0,0 @@
|
|||
/*===---- builtins.h - z/Architecture Builtin Functions --------------------===
|
||||
*
|
||||
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
* See https://llvm.org/LICENSE.txt for license information.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*
|
||||
*===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifndef __ZOS_WRAPPERS_BUILTINS_H
|
||||
#define __ZOS_WRAPPERS_BUILTINS_H
|
||||
#if defined(__MVS__)
|
||||
#include_next <builtins.h>
|
||||
#if defined(__VEC__)
|
||||
#include <vecintrin.h>
|
||||
#endif
|
||||
#endif /* defined(__MVS__) */
|
||||
#endif /* __ZOS_WRAPPERS_BUILTINS_H */
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
// -*- C++ -*-
|
||||
//===-----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_IBM_H
|
||||
#define _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_IBM_H
|
||||
|
||||
#if defined(__MVS__)
|
||||
# include <__support/ibm/locale_mgmt_zos.h>
|
||||
#endif // defined(__MVS__)
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cstdlib"
|
||||
|
||||
#if defined(__MVS__)
|
||||
# include <wctype.h>
|
||||
// POSIX routines
|
||||
# include <__support/xlocale/__posix_l_fallback.h>
|
||||
#endif // defined(__MVS__)
|
||||
|
||||
namespace {
|
||||
|
||||
struct __setAndRestore {
|
||||
explicit __setAndRestore(locale_t locale) {
|
||||
if (locale == (locale_t)0) {
|
||||
__cloc = newlocale(LC_ALL_MASK, "C", /* base */ (locale_t)0);
|
||||
__stored = uselocale(__cloc);
|
||||
} else {
|
||||
__stored = uselocale(locale);
|
||||
}
|
||||
}
|
||||
|
||||
~__setAndRestore() {
|
||||
uselocale(__stored);
|
||||
if (__cloc)
|
||||
freelocale(__cloc);
|
||||
}
|
||||
|
||||
private:
|
||||
locale_t __stored = (locale_t)0;
|
||||
locale_t __cloc = (locale_t)0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// The following are not POSIX routines. These are quick-and-dirty hacks
|
||||
// to make things pretend to work
|
||||
inline _LIBCPP_HIDE_FROM_ABI long long strtoll_l(const char* __nptr, char** __endptr, int __base, locale_t locale) {
|
||||
__setAndRestore __newloc(locale);
|
||||
return ::strtoll(__nptr, __endptr, __base);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI double strtod_l(const char* __nptr, char** __endptr, locale_t locale) {
|
||||
__setAndRestore __newloc(locale);
|
||||
return ::strtod(__nptr, __endptr);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI float strtof_l(const char* __nptr, char** __endptr, locale_t locale) {
|
||||
__setAndRestore __newloc(locale);
|
||||
return ::strtof(__nptr, __endptr);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI long double strtold_l(const char* __nptr, char** __endptr, locale_t locale) {
|
||||
__setAndRestore __newloc(locale);
|
||||
return ::strtold(__nptr, __endptr);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI unsigned long long
|
||||
strtoull_l(const char* __nptr, char** __endptr, int __base, locale_t locale) {
|
||||
__setAndRestore __newloc(locale);
|
||||
return ::strtoull(__nptr, __endptr, __base);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI
|
||||
_LIBCPP_ATTRIBUTE_FORMAT(__printf__, 2, 0) int vasprintf(char** strp, const char* fmt, va_list ap) {
|
||||
const size_t buff_size = 256;
|
||||
if ((*strp = (char*)malloc(buff_size)) == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_list ap_copy;
|
||||
// va_copy may not be provided by the C library in C++03 mode.
|
||||
#if defined(_LIBCPP_CXX03_LANG) && __has_builtin(__builtin_va_copy)
|
||||
__builtin_va_copy(ap_copy, ap);
|
||||
#else
|
||||
va_copy(ap_copy, ap);
|
||||
#endif
|
||||
int str_size = vsnprintf(*strp, buff_size, fmt, ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
if ((size_t)str_size >= buff_size) {
|
||||
if ((*strp = (char*)realloc(*strp, str_size + 1)) == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
str_size = vsnprintf(*strp, str_size + 1, fmt, ap);
|
||||
}
|
||||
return str_size;
|
||||
}
|
||||
|
||||
#endif // _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_IBM_H
|
||||
52
lib/libcxx/include/__support/ibm/gettod_zos.h
vendored
52
lib/libcxx/include/__support/ibm/gettod_zos.h
vendored
|
|
@ -1,52 +0,0 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___SUPPORT_IBM_GETTOD_ZOS_H
|
||||
#define _LIBCPP___SUPPORT_IBM_GETTOD_ZOS_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI int gettimeofdayMonotonic(struct timespec64* Output) {
|
||||
// The POSIX gettimeofday() function is not available on z/OS. Therefore,
|
||||
// we will call stcke and other hardware instructions in implement equivalent.
|
||||
// Note that nanoseconds alone will overflow when reaching new epoch in 2042.
|
||||
|
||||
struct _t {
|
||||
uint64_t Hi;
|
||||
uint64_t Lo;
|
||||
};
|
||||
struct _t Value = {0, 0};
|
||||
uint64_t CC = 0;
|
||||
asm(" stcke %0\n"
|
||||
" ipm %1\n"
|
||||
" srlg %1,%1,28\n"
|
||||
: "=m"(Value), "+r"(CC)::);
|
||||
|
||||
if (CC != 0) {
|
||||
errno = EMVSTODNOTSET;
|
||||
return CC;
|
||||
}
|
||||
uint64_t us = (Value.Hi >> 4);
|
||||
uint64_t ns = ((Value.Hi & 0x0F) << 8) + (Value.Lo >> 56);
|
||||
ns = (ns * 1000) >> 12;
|
||||
us = us - 2208988800000000;
|
||||
|
||||
register uint64_t DivPair0 asm("r0"); // dividend (upper half), remainder
|
||||
DivPair0 = 0;
|
||||
register uint64_t DivPair1 asm("r1"); // dividend (lower half), quotient
|
||||
DivPair1 = us;
|
||||
uint64_t Divisor = 1000000;
|
||||
asm(" dlgr %0,%2" : "+r"(DivPair0), "+r"(DivPair1) : "r"(Divisor) :);
|
||||
|
||||
Output->tv_sec = DivPair1;
|
||||
Output->tv_nsec = DivPair0 * 1000 + ns;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // _LIBCPP___SUPPORT_IBM_GETTOD_ZOS_H
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___SUPPORT_IBM_LOCALE_MGMT_ZOS_H
|
||||
#define _LIBCPP___SUPPORT_IBM_LOCALE_MGMT_ZOS_H
|
||||
|
||||
#if defined(__MVS__)
|
||||
# include <locale.h>
|
||||
# include <string>
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
# define _LC_MAX LC_MESSAGES /* highest real category */
|
||||
# define _NCAT (_LC_MAX + 1) /* maximum + 1 */
|
||||
|
||||
# define _CATMASK(n) (1 << (n))
|
||||
# define LC_COLLATE_MASK _CATMASK(LC_COLLATE)
|
||||
# define LC_CTYPE_MASK _CATMASK(LC_CTYPE)
|
||||
# define LC_MONETARY_MASK _CATMASK(LC_MONETARY)
|
||||
# define LC_NUMERIC_MASK _CATMASK(LC_NUMERIC)
|
||||
# define LC_TIME_MASK _CATMASK(LC_TIME)
|
||||
# define LC_MESSAGES_MASK _CATMASK(LC_MESSAGES)
|
||||
# define LC_ALL_MASK (_CATMASK(_NCAT) - 1)
|
||||
|
||||
typedef struct locale_struct {
|
||||
int category_mask;
|
||||
std::string lc_collate;
|
||||
std::string lc_ctype;
|
||||
std::string lc_monetary;
|
||||
std::string lc_numeric;
|
||||
std::string lc_time;
|
||||
std::string lc_messages;
|
||||
}* locale_t;
|
||||
|
||||
// z/OS does not have newlocale, freelocale and uselocale.
|
||||
// The functions below are workarounds in single thread mode.
|
||||
locale_t newlocale(int category_mask, const char* locale, locale_t base);
|
||||
void freelocale(locale_t locobj);
|
||||
locale_t uselocale(locale_t newloc);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
#endif // defined(__MVS__)
|
||||
#endif // _LIBCPP___SUPPORT_IBM_LOCALE_MGMT_ZOS_H
|
||||
55
lib/libcxx/include/__support/ibm/nanosleep.h
vendored
55
lib/libcxx/include/__support/ibm/nanosleep.h
vendored
|
|
@ -1,55 +0,0 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___SUPPORT_IBM_NANOSLEEP_H
|
||||
#define _LIBCPP___SUPPORT_IBM_NANOSLEEP_H
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
inline int nanosleep(const struct timespec* __req, struct timespec* __rem) {
|
||||
// The nanosleep() function is not available on z/OS. Therefore, we will call
|
||||
// sleep() to sleep for whole seconds and usleep() to sleep for any remaining
|
||||
// fraction of a second. Any remaining nanoseconds will round up to the next
|
||||
// microsecond.
|
||||
if (__req->tv_sec < 0 || __req->tv_nsec < 0 || __req->tv_nsec > 999999999) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
long __micro_sec = (__req->tv_nsec + 999) / 1000;
|
||||
time_t __sec = __req->tv_sec;
|
||||
if (__micro_sec > 999999) {
|
||||
++__sec;
|
||||
__micro_sec -= 1000000;
|
||||
}
|
||||
__sec = static_cast<time_t>(sleep(static_cast<unsigned int>(__sec)));
|
||||
if (__sec) {
|
||||
if (__rem) {
|
||||
// Updating the remaining time to sleep in case of unsuccessful call to sleep().
|
||||
__rem->tv_sec = __sec;
|
||||
__rem->tv_nsec = __micro_sec * 1000;
|
||||
}
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
if (__micro_sec) {
|
||||
int __rt = usleep(static_cast<unsigned int>(__micro_sec));
|
||||
if (__rt != 0 && __rem) {
|
||||
// The usleep() does not provide the amount of remaining time upon its failure,
|
||||
// so the time slept will be ignored.
|
||||
__rem->tv_sec = 0;
|
||||
__rem->tv_nsec = __micro_sec * 1000;
|
||||
// The errno is already set.
|
||||
return -1;
|
||||
}
|
||||
return __rt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // _LIBCPP___SUPPORT_IBM_NANOSLEEP_H
|
||||
97
lib/libcxx/src/support/ibm/mbsnrtowcs.cpp
vendored
97
lib/libcxx/src/support/ibm/mbsnrtowcs.cpp
vendored
|
|
@ -1,97 +0,0 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cwchar> // mbstate_t
|
||||
#include <limits.h> // MB_LEN_MAX
|
||||
#include <string.h> // wmemcpy
|
||||
|
||||
// Returns the number of wide characters found in the multi byte sequence `src`
|
||||
// (of `src_size_bytes`), that fit in the buffer `dst` (of `max_dest_chars`
|
||||
// elements size). The count returned excludes the null terminator.
|
||||
// When `dst` is NULL, no characters are copied to `dst`.
|
||||
// Returns (size_t) -1 when an invalid sequence is encountered.
|
||||
// Leaves *`src` pointing to the next character to convert or NULL
|
||||
// if a null character was converted from *`src`.
|
||||
_LIBCPP_EXPORTED_FROM_ABI size_t mbsnrtowcs(
|
||||
wchar_t* __restrict dst,
|
||||
const char** __restrict src,
|
||||
size_t src_size_bytes,
|
||||
size_t max_dest_chars,
|
||||
mbstate_t* __restrict ps) {
|
||||
const size_t terminated_sequence = static_cast<size_t>(0);
|
||||
const size_t invalid_sequence = static_cast<size_t>(-1);
|
||||
const size_t incomplete_sequence = static_cast<size_t>(-2);
|
||||
|
||||
size_t source_converted;
|
||||
size_t dest_converted;
|
||||
size_t result = 0;
|
||||
|
||||
// If `dst` is null then `max_dest_chars` should be ignored according to the
|
||||
// standard. Setting `max_dest_chars` to a large value has this effect.
|
||||
if (dst == nullptr)
|
||||
max_dest_chars = static_cast<size_t>(-1);
|
||||
|
||||
for (dest_converted = source_converted = 0;
|
||||
source_converted < src_size_bytes && (!dst || dest_converted < max_dest_chars);
|
||||
++dest_converted, source_converted += result) {
|
||||
// Converts one multi byte character.
|
||||
// If result (char_size) is greater than 0, it's the size in bytes of that character.
|
||||
// If result (char_size) is zero, it indicates that the null character has been found.
|
||||
// Otherwise, it's an error and errno may be set.
|
||||
size_t source_remaining = src_size_bytes - source_converted;
|
||||
size_t dest_remaining = max_dest_chars - dest_converted;
|
||||
|
||||
if (dst == nullptr) {
|
||||
result = mbrtowc(nullptr, *src + source_converted, source_remaining, ps);
|
||||
} else if (dest_remaining >= source_remaining) {
|
||||
// dst has enough space to translate in-place.
|
||||
result = mbrtowc(dst + dest_converted, *src + source_converted, source_remaining, ps);
|
||||
} else {
|
||||
/*
|
||||
* dst may not have enough space, so use a temporary buffer.
|
||||
*
|
||||
* We need to save a copy of the conversion state
|
||||
* here so we can restore it if the multibyte
|
||||
* character is too long for the buffer.
|
||||
*/
|
||||
wchar_t buff[MB_LEN_MAX];
|
||||
mbstate_t mbstate_tmp;
|
||||
|
||||
if (ps != nullptr)
|
||||
mbstate_tmp = *ps;
|
||||
result = mbrtowc(buff, *src + source_converted, source_remaining, ps);
|
||||
|
||||
if (result > dest_remaining) {
|
||||
// Multi-byte sequence for character won't fit.
|
||||
if (ps != nullptr)
|
||||
*ps = mbstate_tmp;
|
||||
break;
|
||||
} else {
|
||||
// The buffer was used, so we need copy the translation to dst.
|
||||
wmemcpy(dst, buff, result);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't do anything to change errno from here on.
|
||||
if (result == invalid_sequence || result == terminated_sequence || result == incomplete_sequence) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dst) {
|
||||
if (result == terminated_sequence)
|
||||
*src = nullptr;
|
||||
else
|
||||
*src += source_converted;
|
||||
}
|
||||
if (result == invalid_sequence)
|
||||
return invalid_sequence;
|
||||
|
||||
return dest_converted;
|
||||
}
|
||||
94
lib/libcxx/src/support/ibm/wcsnrtombs.cpp
vendored
94
lib/libcxx/src/support/ibm/wcsnrtombs.cpp
vendored
|
|
@ -1,94 +0,0 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <cwchar> // mbstate_t
|
||||
#include <limits.h> // MB_LEN_MAX
|
||||
#include <stdlib.h> // MB_CUR_MAX, size_t
|
||||
#include <string.h> // memcpy
|
||||
|
||||
// Converts `max_source_chars` from the wide character buffer pointer to by *`src`,
|
||||
// into the multi byte character sequence buffer stored at `dst`, which must be
|
||||
// `dst_size_bytes` bytes in size. Returns the number of bytes in the sequence
|
||||
// converted from *src, excluding the null terminator.
|
||||
// Returns (size_t) -1 if an error occurs and sets errno.
|
||||
// If `dst` is NULL, `dst_size_bytes` is ignored and no bytes are copied to `dst`.
|
||||
_LIBCPP_EXPORTED_FROM_ABI size_t wcsnrtombs(
|
||||
char* __restrict dst,
|
||||
const wchar_t** __restrict src,
|
||||
size_t max_source_chars,
|
||||
size_t dst_size_bytes,
|
||||
mbstate_t* __restrict ps) {
|
||||
const size_t invalid_wchar = static_cast<size_t>(-1);
|
||||
|
||||
size_t source_converted;
|
||||
size_t dest_converted;
|
||||
size_t result = 0;
|
||||
|
||||
// If `dst` is null then `dst_size_bytes` should be ignored according to the
|
||||
// standard. Setting dst_size_bytes to a large value has this effect.
|
||||
if (dst == nullptr)
|
||||
dst_size_bytes = static_cast<size_t>(-1);
|
||||
|
||||
for (dest_converted = source_converted = 0;
|
||||
source_converted < max_source_chars && (!dst || dest_converted < dst_size_bytes);
|
||||
++source_converted, dest_converted += result) {
|
||||
wchar_t c = (*src)[source_converted];
|
||||
size_t dest_remaining = dst_size_bytes - dest_converted;
|
||||
|
||||
if (dst == nullptr) {
|
||||
result = wcrtomb(nullptr, c, ps);
|
||||
} else if (dest_remaining >= static_cast<size_t>(MB_CUR_MAX)) {
|
||||
// dst has enough space to translate in-place.
|
||||
result = wcrtomb(dst + dest_converted, c, ps);
|
||||
} else {
|
||||
/*
|
||||
* dst may not have enough space, so use a temporary buffer.
|
||||
*
|
||||
* We need to save a copy of the conversion state
|
||||
* here so we can restore it if the multibyte
|
||||
* character is too long for the buffer.
|
||||
*/
|
||||
char buff[MB_LEN_MAX];
|
||||
mbstate_t mbstate_tmp;
|
||||
|
||||
if (ps != nullptr)
|
||||
mbstate_tmp = *ps;
|
||||
result = wcrtomb(buff, c, ps);
|
||||
|
||||
if (result > dest_remaining) {
|
||||
// Multi-byte sequence for character won't fit.
|
||||
if (ps != nullptr)
|
||||
*ps = mbstate_tmp;
|
||||
if (result != invalid_wchar)
|
||||
break;
|
||||
} else {
|
||||
// The buffer was used, so we need copy the translation to dst.
|
||||
memcpy(dst, buff, result);
|
||||
}
|
||||
}
|
||||
|
||||
// result (char_size) contains the size of the multi-byte-sequence converted.
|
||||
// Otherwise, result (char_size) is (size_t) -1 and wcrtomb() sets the errno.
|
||||
if (result == invalid_wchar) {
|
||||
if (dst)
|
||||
*src = *src + source_converted;
|
||||
return invalid_wchar;
|
||||
}
|
||||
|
||||
if (c == L'\0') {
|
||||
if (dst)
|
||||
*src = nullptr;
|
||||
return dest_converted;
|
||||
}
|
||||
}
|
||||
|
||||
if (dst)
|
||||
*src = *src + source_converted;
|
||||
|
||||
return dest_converted;
|
||||
}
|
||||
130
lib/libcxx/src/support/ibm/xlocale_zos.cpp
vendored
130
lib/libcxx/src/support/ibm/xlocale_zos.cpp
vendored
|
|
@ -1,130 +0,0 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <__assert>
|
||||
#include <__support/ibm/xlocale.h>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
locale_t newlocale(int category_mask, const char* locale, locale_t base) {
|
||||
// Maintain current locale name(s) to restore later.
|
||||
std::string current_loc_name(setlocale(LC_ALL, 0));
|
||||
|
||||
// Check for errors.
|
||||
if (category_mask == LC_ALL_MASK && setlocale(LC_ALL, locale) == nullptr) {
|
||||
errno = EINVAL;
|
||||
return (locale_t)0;
|
||||
} else {
|
||||
for (int _Cat = 0; _Cat <= _LC_MAX; ++_Cat) {
|
||||
if ((_CATMASK(_Cat) & category_mask) != 0 && setlocale(_Cat, locale) == nullptr) {
|
||||
setlocale(LC_ALL, current_loc_name.c_str());
|
||||
errno = EINVAL;
|
||||
return (locale_t)0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create new locale.
|
||||
locale_t newloc = new locale_struct();
|
||||
|
||||
if (base) {
|
||||
if (category_mask != LC_ALL_MASK) {
|
||||
// Copy base when it will not be overwritten.
|
||||
memcpy(newloc, base, sizeof(locale_struct));
|
||||
newloc->category_mask = category_mask | base->category_mask;
|
||||
}
|
||||
delete base;
|
||||
} else {
|
||||
newloc->category_mask = category_mask;
|
||||
}
|
||||
|
||||
if (category_mask & LC_COLLATE_MASK)
|
||||
newloc->lc_collate = locale;
|
||||
if (category_mask & LC_CTYPE_MASK)
|
||||
newloc->lc_ctype = locale;
|
||||
if (category_mask & LC_MONETARY_MASK)
|
||||
newloc->lc_monetary = locale;
|
||||
if (category_mask & LC_NUMERIC_MASK)
|
||||
newloc->lc_numeric = locale;
|
||||
if (category_mask & LC_TIME_MASK)
|
||||
newloc->lc_time = locale;
|
||||
if (category_mask & LC_MESSAGES_MASK)
|
||||
newloc->lc_messages = locale;
|
||||
|
||||
// Restore current locale.
|
||||
setlocale(LC_ALL, current_loc_name.c_str());
|
||||
return (locale_t)newloc;
|
||||
}
|
||||
|
||||
void freelocale(locale_t locobj) { delete locobj; }
|
||||
|
||||
locale_t uselocale(locale_t newloc) {
|
||||
// Maintain current locale name(s).
|
||||
std::string current_loc_name(setlocale(LC_ALL, 0));
|
||||
|
||||
if (newloc) {
|
||||
// Set locales and check for errors.
|
||||
bool is_error =
|
||||
(newloc->category_mask & LC_COLLATE_MASK && setlocale(LC_COLLATE, newloc->lc_collate.c_str()) == nullptr) ||
|
||||
(newloc->category_mask & LC_CTYPE_MASK && setlocale(LC_CTYPE, newloc->lc_ctype.c_str()) == nullptr) ||
|
||||
(newloc->category_mask & LC_MONETARY_MASK && setlocale(LC_MONETARY, newloc->lc_monetary.c_str()) == nullptr) ||
|
||||
(newloc->category_mask & LC_NUMERIC_MASK && setlocale(LC_NUMERIC, newloc->lc_numeric.c_str()) == nullptr) ||
|
||||
(newloc->category_mask & LC_TIME_MASK && setlocale(LC_TIME, newloc->lc_time.c_str()) == nullptr) ||
|
||||
(newloc->category_mask & LC_MESSAGES_MASK && setlocale(LC_MESSAGES, newloc->lc_messages.c_str()) == nullptr);
|
||||
|
||||
if (is_error) {
|
||||
setlocale(LC_ALL, current_loc_name.c_str());
|
||||
errno = EINVAL;
|
||||
return (locale_t)0;
|
||||
}
|
||||
}
|
||||
|
||||
// Construct and return previous locale.
|
||||
locale_t previous_loc = new locale_struct();
|
||||
|
||||
// current_loc_name might be a comma-separated locale name list.
|
||||
if (current_loc_name.find(',') != std::string::npos) {
|
||||
// Tokenize locale name list.
|
||||
const char delimiter = ',';
|
||||
std::vector<std::string> tokenized;
|
||||
std::stringstream ss(current_loc_name);
|
||||
std::string s;
|
||||
|
||||
while (std::getline(ss, s, delimiter)) {
|
||||
tokenized.push_back(s);
|
||||
}
|
||||
|
||||
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(tokenized.size() >= _NCAT, "locale-name list is too short");
|
||||
|
||||
previous_loc->lc_collate = tokenized[LC_COLLATE];
|
||||
previous_loc->lc_ctype = tokenized[LC_CTYPE];
|
||||
previous_loc->lc_monetary = tokenized[LC_MONETARY];
|
||||
previous_loc->lc_numeric = tokenized[LC_NUMERIC];
|
||||
previous_loc->lc_time = tokenized[LC_TIME];
|
||||
// Skip LC_TOD.
|
||||
previous_loc->lc_messages = tokenized[LC_MESSAGES];
|
||||
} else {
|
||||
previous_loc->lc_collate = current_loc_name;
|
||||
previous_loc->lc_ctype = current_loc_name;
|
||||
previous_loc->lc_monetary = current_loc_name;
|
||||
previous_loc->lc_numeric = current_loc_name;
|
||||
previous_loc->lc_time = current_loc_name;
|
||||
previous_loc->lc_messages = current_loc_name;
|
||||
}
|
||||
|
||||
previous_loc->category_mask = LC_ALL_MASK;
|
||||
return previous_loc;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
745
lib/libcxxabi/src/aix_state_tab_eh.inc
vendored
745
lib/libcxxabi/src/aix_state_tab_eh.inc
vendored
|
|
@ -1,745 +0,0 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//
|
||||
// This file implements the personality and helper functions for the state
|
||||
// table based EH used by IBM legacy compilers xlC and xlclang++ on AIX.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <sys/debug.h>
|
||||
|
||||
/*
|
||||
The legacy IBM xlC and xlclang++ compilers use the state table for EH
|
||||
instead of the range table. Destructors, or addresses of the possible catch
|
||||
sites or cleanup code are specified in the state table which is a finite
|
||||
state machine (FSM). Each function that has a state table also has an
|
||||
autolocal state variable. The state variable represents the current state
|
||||
of the function for EH and is found through the traceback table of the
|
||||
function during unwinding, which is located at the end of each function.
|
||||
The FSM is an array of state entries. Each state entry has the following
|
||||
fields:
|
||||
|
||||
* offset/address/pointer - the offset used to locate the object, or the
|
||||
address of a global object, or the address of the next state if it is an
|
||||
old conditional state change entry;
|
||||
* dtor/landing pad - address of the destructor function to invoke,
|
||||
or address of the catch block or cleanup code in the user code to branch to;
|
||||
* element count/action flag - the number of elements or the flag for actions;
|
||||
* element size - if the object is an array this is the size of one element
|
||||
of the array;
|
||||
* flags - flags used to control how fields in the entry are interpreted;
|
||||
* next state - the state to execute next after the action for this state is
|
||||
performed. The value of zero indicates the end of the state for this
|
||||
function.
|
||||
|
||||
The following is the description of 'element count/action flag' field.
|
||||
+-----------------------------------------------------------------------------+
|
||||
| value | description | action |
|
||||
+-------+------------------------+--------------------------------------------+
|
||||
| > 1 | object is an array | calls __cxa_vec_cleanup to run dtor for |
|
||||
| | | each member of the array |
|
||||
+-------+------------------------+--------------------------------------------+
|
||||
| 1, 0 | object is a scalar | calls dtor for the object |
|
||||
+-------+------------------------+--------------------------------------------+
|
||||
| -1 | begin catch | branches to the handler which performes |
|
||||
| | | catch-match. If there is no catch that |
|
||||
| | | matches the exception it will be rethrown |
|
||||
+-------+------------------------+--------------------------------------------+
|
||||
| -2 | end catch | ends current catch block and continues |
|
||||
| | | attempting to catch the exception |
|
||||
+-------+------------------------+--------------------------------------------+
|
||||
| -3 | delete the object | calls the delete function of the object |
|
||||
+-------+------------------------+--------------------------------------------+
|
||||
| -4 | cleanup label | branches to the user code for cleaning up |
|
||||
+-------+------------------------+--------------------------------------------+
|
||||
*/
|
||||
|
||||
namespace __cxxabiv1 {
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Macros for debugging the state table parsing.
|
||||
#ifdef NDEBUG
|
||||
# define _LIBCXXABI_TRACE_STATETAB(msg, ...)
|
||||
# define _LIBCXXABI_TRACE_STATETAB0(msg)
|
||||
# define _LIBCXXABI_TRACE_STATETAB1(msg)
|
||||
# define _LIBCXXABI_TRACING_STATETAB 0
|
||||
#else
|
||||
static bool state_tab_dbg() {
|
||||
static bool checked = false;
|
||||
static bool log = false;
|
||||
if (!checked) {
|
||||
log = (getenv("LIBCXXABI_PRINT_STATTAB") != NULL);
|
||||
checked = true;
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
# define _LIBCXXABI_TRACE_STATETAB(msg, ...) \
|
||||
do { \
|
||||
if (state_tab_dbg()) \
|
||||
fprintf(stderr, "libcxxabi: " msg, __VA_ARGS__); \
|
||||
} while (0)
|
||||
# define _LIBCXXABI_TRACE_STATETAB0(msg) \
|
||||
do { \
|
||||
if (state_tab_dbg()) \
|
||||
fprintf(stderr, "libcxxabi: " msg); \
|
||||
} while (0)
|
||||
# define _LIBCXXABI_TRACE_STATETAB1(msg) \
|
||||
do { \
|
||||
if (state_tab_dbg()) \
|
||||
fprintf(stderr, msg); \
|
||||
} while (0)
|
||||
|
||||
# define _LIBCXXABI_TRACING_STATETAB state_tab_dbg()
|
||||
#endif // NDEBUG
|
||||
|
||||
namespace __state_table_eh {
|
||||
|
||||
// Definition of flags for the state table entry field 'action flag'.
|
||||
enum FSMEntryCount : intptr_t { beginCatch = -1, endCatch = -2, deleteObject = -3, cleanupLabel = -4, terminate = -5 };
|
||||
|
||||
// Definition of flags for the state table entry field 'flags'.
|
||||
enum FSMEntryFlag : int16_t {
|
||||
indirect = 0x100, // Object was thrown from a function where
|
||||
// the return value optimization was used.
|
||||
oldConditionalStateChange = 0x400, // State table entry is an indirect state
|
||||
// change, dereference the address in
|
||||
// offset as int for the target state.
|
||||
// This is deprecated. This indicates
|
||||
// the address is direct. (static local).
|
||||
conditionalStateChange = 0x800, // State table entry is an indirect state
|
||||
// change, dereference the address in
|
||||
// offset as int for the target state.
|
||||
// The temporary is an automatic. State
|
||||
// change is used in cases such as
|
||||
// (b?(T1(),foo()):(T2(),foo())),throw 42;
|
||||
// which causes a conditional state change
|
||||
// so that we know if T1 or T2 need to be
|
||||
// destroyed.
|
||||
thisFlag = 0x01, // The address of the object for the
|
||||
// cleanup action is based on the
|
||||
// StateVariable::thisValue.
|
||||
vBaseFlag = 0x02, // The object is of a virtual base class.
|
||||
globalObj = 0x04 // FSMEntry::address is the address of
|
||||
// a global object.
|
||||
};
|
||||
|
||||
namespace {
|
||||
// The finite state machine to be walked.
|
||||
struct FSMEntry {
|
||||
union {
|
||||
// Offset of the object within its stack frame or containing object.
|
||||
intptr_t offset;
|
||||
// Address of a global object.
|
||||
intptr_t address;
|
||||
// Address of the next state if it is an old conditional state change entry.
|
||||
intptr_t nextStatePtr;
|
||||
};
|
||||
union {
|
||||
// Address of the destructor function with 1 argument.
|
||||
void (*destructor)(void*);
|
||||
// Address of the destructor function with 2 arguments.
|
||||
void (*xlCDestructor)(void*, size_t);
|
||||
// The address of the catch block or cleanup code.
|
||||
void* landingPad;
|
||||
};
|
||||
union {
|
||||
// The flag for actions (when the value is negative).
|
||||
FSMEntryCount actionFlag;
|
||||
// The element count (when the value is positive or zero).
|
||||
size_t elementCount;
|
||||
};
|
||||
size_t elemSize;
|
||||
FSMEntryFlag flags;
|
||||
uint16_t nextState;
|
||||
};
|
||||
|
||||
struct FSM {
|
||||
uint32_t magic; // Magic number of the state table.
|
||||
int32_t numberOfStates;
|
||||
FSMEntry table[1]; // Actually table[numberOfStates].
|
||||
};
|
||||
|
||||
// The state variable on the stack.
|
||||
struct StateVariable {
|
||||
int32_t state;
|
||||
struct FSM* table;
|
||||
intptr_t thisValue;
|
||||
int32_t ignoreVBasePtrs;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// State table magic number
|
||||
enum FSMMagic : uint32_t {
|
||||
number = 0xbeefdead, // State table generated by xlC compiler.
|
||||
number2 = 0xbeeedead, // State table generated by early version xlC compiler.
|
||||
number3 = 0x1cedbeef // State table generated by xlclang++ compiler.
|
||||
};
|
||||
|
||||
constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free
|
||||
// virtual bases, don't delete object.
|
||||
|
||||
static void invoke_destructor(FSMEntry* fsmEntry, void* addr) {
|
||||
_LIBCXXABI_TRACE_STATETAB("Destruct object=%p, fsmEntry=%p\n", addr, reinterpret_cast<void*>(fsmEntry));
|
||||
try {
|
||||
if (fsmEntry->elementCount == 1) {
|
||||
_LIBCXXABI_TRACE_STATETAB0("calling scalar destructor\n");
|
||||
(*fsmEntry->xlCDestructor)(addr, dtorArgument);
|
||||
_LIBCXXABI_TRACE_STATETAB0("returned from scalar destructor\n");
|
||||
} else {
|
||||
_LIBCXXABI_TRACE_STATETAB0("calling vector destructor\n");
|
||||
__cxa_vec_cleanup(addr, reinterpret_cast<size_t>(fsmEntry->elementCount), fsmEntry->elemSize,
|
||||
fsmEntry->destructor);
|
||||
_LIBCXXABI_TRACE_STATETAB0("returned from vector destructor\n");
|
||||
}
|
||||
} catch (...) {
|
||||
_LIBCXXABI_TRACE_STATETAB0("Uncaught exception in destructor, terminating\n");
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
static void invoke_delete(FSMEntry* fsmEntry, void* addr) {
|
||||
char* objectAddress = *reinterpret_cast<char**>(addr);
|
||||
|
||||
_LIBCXXABI_TRACE_STATETAB("Delete object=%p, fsmEntry=%p\n", reinterpret_cast<void*>(objectAddress),
|
||||
reinterpret_cast<void*>(fsmEntry));
|
||||
try {
|
||||
_LIBCXXABI_TRACE_STATETAB0("..calling delete()\n");
|
||||
// 'destructor' holds a function pointer to delete().
|
||||
(*fsmEntry->xlCDestructor)(objectAddress, fsmEntry->elemSize);
|
||||
_LIBCXXABI_TRACE_STATETAB0("..returned from delete()\n");
|
||||
} catch (...) {
|
||||
_LIBCXXABI_TRACE_STATETAB0("Uncaught exception in delete(), terminating\n");
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
// Get the frame address of the current function from its traceback table
|
||||
// which is at the end of each function.
|
||||
static uintptr_t get_frame_addr(_Unwind_Context* context) {
|
||||
int framePointerReg = 1; // default frame pointer == SP.
|
||||
uint32_t* p = reinterpret_cast<uint32_t*>(_Unwind_GetIP(context));
|
||||
|
||||
// Keep looking forward until a word of 0 is found. The traceback
|
||||
// table starts at the following word.
|
||||
while (*p)
|
||||
++p;
|
||||
tbtable* TBTable = reinterpret_cast<tbtable*>(p + 1);
|
||||
|
||||
p = reinterpret_cast<uint32_t*>(&TBTable->tb_ext);
|
||||
|
||||
// Skip field parminfo if it exists.
|
||||
if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
|
||||
++p;
|
||||
|
||||
// Skip field tb_offset if it exists.
|
||||
if (TBTable->tb.has_tboff)
|
||||
++p;
|
||||
|
||||
// Skip field hand_mask if it exists.
|
||||
if (TBTable->tb.int_hndl)
|
||||
++p;
|
||||
|
||||
// Skip fields ctl_info and ctl_info_disp if they exist.
|
||||
if (TBTable->tb.has_ctl)
|
||||
p += 1 + *p;
|
||||
|
||||
// Skip fields name_len and name if exist.
|
||||
if (TBTable->tb.name_present) {
|
||||
const uint16_t name_len = *reinterpret_cast<uint16_t*>(p);
|
||||
p = reinterpret_cast<uint32_t*>(reinterpret_cast<char*>(p) + name_len + sizeof(uint16_t));
|
||||
}
|
||||
|
||||
if (TBTable->tb.uses_alloca)
|
||||
framePointerReg = *reinterpret_cast<char*>(p);
|
||||
|
||||
return _Unwind_GetGR(context, framePointerReg);
|
||||
}
|
||||
|
||||
// Calculate the object address from the FSM entry.
|
||||
static void* compute_addr_from_table(FSMEntry* fsmEntry, StateVariable* const state, _Unwind_Context* context) {
|
||||
void* addr;
|
||||
if (fsmEntry->flags & FSMEntryFlag::globalObj) {
|
||||
addr = reinterpret_cast<void*>(fsmEntry->address);
|
||||
_LIBCXXABI_TRACE_STATETAB("Address calculation (global obj) addr=fsmEntry->address=%p\n", addr);
|
||||
} else if (fsmEntry->flags & FSMEntryFlag::thisFlag) {
|
||||
addr = reinterpret_cast<void*>(state->thisValue + fsmEntry->offset);
|
||||
_LIBCXXABI_TRACE_STATETAB("Address calculation (this obj) fsmEntry->offset=%ld : "
|
||||
"state->thisValue=%ld addr=(fsmEntry->offset+state->thisValue)=%p\n",
|
||||
fsmEntry->offset, state->thisValue, addr);
|
||||
} else if (fsmEntry->flags & FSMEntryFlag::indirect) {
|
||||
addr = reinterpret_cast<void*>(
|
||||
*reinterpret_cast<char**>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset)));
|
||||
_LIBCXXABI_TRACE_STATETAB("Address calculation (indirect obj) addr=%p, fsmEntry->offset=%ld \n",
|
||||
addr, fsmEntry->offset);
|
||||
} else {
|
||||
addr = reinterpret_cast<void*>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset));
|
||||
_LIBCXXABI_TRACE_STATETAB("Address calculation. (local obj) addr=fsmEntry->offset=%p\n",
|
||||
addr);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void scan_state_tab(scan_results& results, _Unwind_Action actions, bool native_exception,
|
||||
_Unwind_Exception* unwind_exception, _Unwind_Context* context) {
|
||||
// Initialize results to found nothing but an error.
|
||||
results.ttypeIndex = 0;
|
||||
results.actionRecord = 0;
|
||||
results.languageSpecificData = 0;
|
||||
results.landingPad = 0;
|
||||
results.adjustedPtr = 0;
|
||||
results.reason = _URC_FATAL_PHASE1_ERROR;
|
||||
|
||||
// Check for consistent actions.
|
||||
if (actions & _UA_SEARCH_PHASE) {
|
||||
// Do Phase 1
|
||||
if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) {
|
||||
// None of these flags should be set during Phase 1.
|
||||
// Client error
|
||||
results.reason = _URC_FATAL_PHASE1_ERROR;
|
||||
return;
|
||||
}
|
||||
} else if (actions & _UA_CLEANUP_PHASE) {
|
||||
if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND)) {
|
||||
// _UA_HANDLER_FRAME should only be set if phase 1 found a handler.
|
||||
// If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened.
|
||||
// Client error
|
||||
results.reason = _URC_FATAL_PHASE2_ERROR;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set.
|
||||
// Client error
|
||||
results.reason = _URC_FATAL_PHASE1_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_LIBCXXABI_TRACING_STATETAB) {
|
||||
_LIBCXXABI_TRACE_STATETAB1("\n");
|
||||
_LIBCXXABI_TRACE_STATETAB("%s: actions=%d (", __func__, actions);
|
||||
|
||||
if (_UA_SEARCH_PHASE & actions)
|
||||
_LIBCXXABI_TRACE_STATETAB1("_UA_SEARCH_PHASE ");
|
||||
if (_UA_CLEANUP_PHASE & actions)
|
||||
_LIBCXXABI_TRACE_STATETAB1("_UA_CLEANUP_PHASE ");
|
||||
if (_UA_HANDLER_FRAME & actions)
|
||||
_LIBCXXABI_TRACE_STATETAB1("_UA_HANDLER_FRAME ");
|
||||
if (_UA_FORCE_UNWIND & actions)
|
||||
_LIBCXXABI_TRACE_STATETAB1("_UA_FORCE_UNWIND ");
|
||||
_LIBCXXABI_TRACE_STATETAB1(")\n");
|
||||
_LIBCXXABI_TRACE_STATETAB(" unwind_exception=%p context=%p\n", reinterpret_cast<void*>(unwind_exception),
|
||||
reinterpret_cast<void*>(context));
|
||||
}
|
||||
|
||||
// Start scan by getting state table address.
|
||||
StateVariable* const state = reinterpret_cast<StateVariable* const>(_Unwind_GetLanguageSpecificData(context));
|
||||
if (state->state <= 0) {
|
||||
// The state is not correct - give up on this routine.
|
||||
_LIBCXXABI_TRACE_STATETAB("state=%d and is <= 0), continue unwinding\n", state->state);
|
||||
results.reason = _URC_CONTINUE_UNWIND;
|
||||
return;
|
||||
}
|
||||
// Parse the state table.
|
||||
FSM* const fsm = state->table;
|
||||
FSMEntry* currFSMEntry;
|
||||
|
||||
if (fsm->magic != FSMMagic::number && fsm->magic != FSMMagic::number2 && fsm->magic != FSMMagic::number3) {
|
||||
// Something is wrong with the state table we found.
|
||||
if (_UA_SEARCH_PHASE & actions) {
|
||||
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE1_ERROR\n");
|
||||
results.reason = _URC_FATAL_PHASE1_ERROR;
|
||||
} else if (_UA_CLEANUP_PHASE & actions) {
|
||||
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE2_ERROR\n");
|
||||
results.reason = _URC_FATAL_PHASE2_ERROR;
|
||||
} else {
|
||||
// We should never get here.
|
||||
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table + RT Internal error, return _URC_FATAL_PHASE2_ERROR\n");
|
||||
results.reason = _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_LIBCXXABI_TRACING_STATETAB) {
|
||||
// Print the state table for debugging purposes.
|
||||
_LIBCXXABI_TRACE_STATETAB("state->state=%d, state->ignoreVBasePtrs=%d\n", state->state, state->ignoreVBasePtrs);
|
||||
_LIBCXXABI_TRACE_STATETAB("fsm->magic=%#x, fsm->numberOfStates=%d\n", fsm->magic, fsm->numberOfStates);
|
||||
// Print out the FSM table.
|
||||
_LIBCXXABI_TRACE_STATETAB0("FSM table:\n");
|
||||
_LIBCXXABI_TRACE_STATETAB("%12s %10s %8s %10s %7s %7s %7s %7s\n", "Entry Addr", "state", "Offset", "DTR/lpad",
|
||||
"count", "el_size", "flags", "next");
|
||||
for (int i = 0; i < fsm->numberOfStates; i++) {
|
||||
currFSMEntry = &fsm->table[i];
|
||||
_LIBCXXABI_TRACE_STATETAB("%12p (%8d) %8ld %10p %7ld "
|
||||
"%7ld %#7x %7d\n",
|
||||
reinterpret_cast<void*>(&currFSMEntry), i + 1, currFSMEntry->offset,
|
||||
reinterpret_cast<void*>(currFSMEntry->destructor),
|
||||
currFSMEntry->elementCount, currFSMEntry->elemSize, currFSMEntry->flags,
|
||||
currFSMEntry->nextState);
|
||||
}
|
||||
}
|
||||
|
||||
if (_UA_SEARCH_PHASE & actions) {
|
||||
// Start walking the state table. Use a local copy of state->state so when
|
||||
// we return from search phase we don't change the state number.
|
||||
int currState = state->state;
|
||||
|
||||
while (currState > 0) {
|
||||
currFSMEntry = &fsm->table[currState - 1];
|
||||
_LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", currState, currFSMEntry->flags);
|
||||
|
||||
if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch) {
|
||||
// Found a catch handler.
|
||||
if (fsm->magic == FSMMagic::number) {
|
||||
_LIBCXXABI_TRACE_STATETAB0("Found a xlC catch handler, return _URC_FATAL_PHASE1_ERROR\n");
|
||||
// xlC catch handlers cannot be entered because they use a
|
||||
// proprietary EH runtime that is not interoperable.
|
||||
results.reason = _URC_FATAL_PHASE1_ERROR;
|
||||
return;
|
||||
}
|
||||
// xlclang++ compiled frames use CXA-abi EH calls and any catch
|
||||
// block will include a catch(...) block so it is safe to assume that
|
||||
// the handler is found without checking the catch match. The
|
||||
// catch(...) block will rethrow the exception if there isn't a
|
||||
// match.
|
||||
_LIBCXXABI_TRACE_STATETAB0("Found a catch handler, return _URC_HANDLER_FOUND\n");
|
||||
results.reason = _URC_HANDLER_FOUND;
|
||||
return;
|
||||
}
|
||||
if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
|
||||
_LIBCXXABI_TRACE_STATETAB0("Found the terminate state, return _URC_HANDLER_FOUND\n");
|
||||
results.reason = _URC_HANDLER_FOUND;
|
||||
return;
|
||||
}
|
||||
if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
|
||||
// Deprecated conditional expression.
|
||||
currState = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
|
||||
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
|
||||
"currFSMEntry->nextStatePtr(%ld), set state=%d\n",
|
||||
currFSMEntry->nextStatePtr, currState);
|
||||
continue; // We are done this iteration of the loop, since
|
||||
// we changed a state.
|
||||
}
|
||||
if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
|
||||
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
||||
currState = *reinterpret_cast<int*>(addr);
|
||||
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
|
||||
"addr(%p), set state=%d\n", addr, currState);
|
||||
continue; // We are done this iteration of the loop, since we
|
||||
// changed the state.
|
||||
}
|
||||
// Go to the next state.
|
||||
currState = currFSMEntry->nextState;
|
||||
}
|
||||
_LIBCXXABI_TRACE_STATETAB0("No catch handler found, return _URC_CONTINUE_UNWIND\n");
|
||||
results.reason = _URC_CONTINUE_UNWIND;
|
||||
return;
|
||||
}
|
||||
if (_UA_CLEANUP_PHASE & actions) {
|
||||
// Start walking the state table.
|
||||
while (state->state > 0) {
|
||||
currFSMEntry = &fsm->table[state->state - 1];
|
||||
|
||||
if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
|
||||
_LIBCXXABI_TRACE_STATETAB0("Reached terminate state. Call terminate.\n");
|
||||
std::terminate();
|
||||
}
|
||||
// Perform action according to the currFSMEntry->actionFlag,
|
||||
// except when flag is FSMEntryFlag::conditionalStateChange or
|
||||
// FSMEntryFlag::oldConditionalStateChange.
|
||||
_LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", state->state, currFSMEntry->flags);
|
||||
if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
|
||||
state->state = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
|
||||
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
|
||||
"currFSMEntry->nextStatePtr(%ld), set state=%d\n",
|
||||
currFSMEntry->nextStatePtr, state->state);
|
||||
continue; // We are done with this iteration of the loop, since we changed a state.
|
||||
}
|
||||
if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
|
||||
// A conditional state table entry holds the address of a local
|
||||
// that holds the next state.
|
||||
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
||||
state->state = *reinterpret_cast<int*>(addr);
|
||||
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
|
||||
"addr(%p), set state=%d\n", addr, state->state);
|
||||
continue; // We are done with this iteration of the loop, since we changed a state.
|
||||
}
|
||||
if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch || currFSMEntry->actionFlag == FSMEntryCount::endCatch ||
|
||||
currFSMEntry->actionFlag == FSMEntryCount::cleanupLabel) {
|
||||
|
||||
_LIBCXXABI_TRACE_STATETAB(
|
||||
"FSMEntryCount::%s: handler %p/%p, return _URC_HANDLER_FOUND\n",
|
||||
(currFSMEntry->actionFlag == FSMEntryCount::beginCatch
|
||||
? "beginCatch"
|
||||
: (currFSMEntry->actionFlag == FSMEntryCount::endCatch ? "endCatch" : "cleanupLabel")),
|
||||
currFSMEntry->landingPad, *reinterpret_cast<void**>(currFSMEntry->landingPad));
|
||||
|
||||
state->state = currFSMEntry->nextState;
|
||||
results.landingPad = reinterpret_cast<uintptr_t>(*reinterpret_cast<void**>(currFSMEntry->landingPad));
|
||||
results.reason = _URC_HANDLER_FOUND;
|
||||
return;
|
||||
}
|
||||
if (currFSMEntry->elementCount > 0) {
|
||||
if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag && state->ignoreVBasePtrs) {
|
||||
_LIBCXXABI_TRACE_STATETAB0("Ignoring virtual base dtor.\n");
|
||||
} else {
|
||||
// We need to invoke the virtual base destructor. This must be
|
||||
// a frame from the legacy xlC compiler as the xlclang++ compiler
|
||||
// generates inline cleanup code rather than specifying
|
||||
// the destructor via the state table.
|
||||
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
||||
|
||||
// An extra indirect to get to the object according to the object
|
||||
// model used by the xlC compiler.
|
||||
addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
|
||||
_LIBCXXABI_TRACE_STATETAB("Invoke dtor for object=%p\n", addr);
|
||||
invoke_destructor(currFSMEntry, addr);
|
||||
}
|
||||
} else if (currFSMEntry->actionFlag == FSMEntryCount::deleteObject) {
|
||||
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
||||
if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag) {
|
||||
// We need to invoke the virtual base delete function. This must be
|
||||
// a frame from the legacy xlC compiler as the xlclang++ compiler
|
||||
// generates inline cleanup code rather than specifying
|
||||
// the delete function via the state table.
|
||||
|
||||
// An extra indirect to get to the object according to the object
|
||||
// model used by the xlC compiler.
|
||||
addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
|
||||
}
|
||||
_LIBCXXABI_TRACE_STATETAB("Delete object at %p\n", addr);
|
||||
invoke_delete(currFSMEntry, addr);
|
||||
} else {
|
||||
_LIBCXXABI_TRACE_STATETAB("Unknown entry in FSM (count=%ld), ignored\n",
|
||||
currFSMEntry->elementCount);
|
||||
} // End of action switching.
|
||||
|
||||
// Go to next state.
|
||||
state->state = currFSMEntry->nextState;
|
||||
}
|
||||
_LIBCXXABI_TRACE_STATETAB0("No catch handler, return _URC_CONTINUE_UNWIND\n");
|
||||
results.reason = _URC_CONTINUE_UNWIND;
|
||||
return;
|
||||
}
|
||||
_LIBCXXABI_TRACE_STATETAB0("No state table entry for this exception, call_terminate()\n");
|
||||
// It is possible that no state table entry specify how to handle
|
||||
// this exception. By spec, terminate it immediately.
|
||||
call_terminate(native_exception, unwind_exception);
|
||||
}
|
||||
|
||||
// Personality routine for EH using the state table.
|
||||
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
|
||||
__xlcxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass,
|
||||
_Unwind_Exception* unwind_exception, _Unwind_Context* context) {
|
||||
if (version != 1 || unwind_exception == 0 || context == 0)
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
|
||||
bool native_exception = (exceptionClass & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language);
|
||||
scan_results results;
|
||||
scan_state_tab(results, actions, native_exception, unwind_exception, context);
|
||||
if (actions & _UA_SEARCH_PHASE) {
|
||||
// Phase 1 search: All we're looking for in phase 1 is a handler that
|
||||
// halts unwinding
|
||||
return results.reason;
|
||||
}
|
||||
if (actions & _UA_CLEANUP_PHASE) {
|
||||
// Phase 2 cleanup:
|
||||
if (results.reason == _URC_HANDLER_FOUND) {
|
||||
// Store the address of unwind_exception in the stack field
|
||||
// reserved for compilers (SP + 3 * sizeof(uintptr_t)) in the stack of
|
||||
// the caller of the function containing the landing pad (within the link
|
||||
// area for the call to the latter) for __xlc_exception_handle()
|
||||
// to retrieve when it is called by the landing pad.
|
||||
uintptr_t *currentSP = reinterpret_cast<uintptr_t*>(_Unwind_GetGR(context, 1));
|
||||
uintptr_t *callersSP = reinterpret_cast<uintptr_t*>(currentSP[0]);
|
||||
callersSP[3] = reinterpret_cast<uintptr_t>(unwind_exception);
|
||||
_LIBCXXABI_TRACE_STATETAB("Handshake: save unwind_exception=%p in stack=%p\n",
|
||||
reinterpret_cast<void*>(unwind_exception), reinterpret_cast<void*>(callersSP));
|
||||
// Jump to the handler.
|
||||
_Unwind_SetIP(context, results.landingPad);
|
||||
return _URC_INSTALL_CONTEXT;
|
||||
}
|
||||
// Did not find a handler. Return the results of the scan. Normally
|
||||
// _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR.
|
||||
return results.reason;
|
||||
}
|
||||
// We were called improperly: neither a phase 1 or phase 2 search.
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
} // namespace __state_table_eh
|
||||
|
||||
// The following are EH helper functions for xlclang++ compiled code.
|
||||
|
||||
// __xlc_catch_matchv2
|
||||
// Check whether the thrown object matches the catch handler's exception
|
||||
// declaration. If there is a match, the function returns true with adjusted
|
||||
// address of the thrown object. Otherwise, returns false.
|
||||
_LIBCXXABI_FUNC_VIS bool
|
||||
__xlc_catch_matchv2(_Unwind_Exception* exceptionObject, std::type_info* catchTypeInfo, void*& obj) {
|
||||
_LIBCXXABI_TRACE_STATETAB("Entering %s, exceptionObject=%p\n", __func__, reinterpret_cast<void*>(exceptionObject));
|
||||
|
||||
if (!__isOurExceptionClass(exceptionObject)) {
|
||||
_LIBCXXABI_TRACE_STATETAB0("No match, not a C++ exception\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
__cxa_exception* exceptionHeader = 0;
|
||||
|
||||
if (__getExceptionClass(exceptionObject) == kOurDependentExceptionClass) {
|
||||
// Walk to the __cxa_dependent_exception primary exception for the
|
||||
// exception object and its type_info.
|
||||
__cxa_dependent_exception* dependentExceptionHeader =
|
||||
reinterpret_cast<__cxa_dependent_exception*>(exceptionObject + 1) - 1;
|
||||
exceptionHeader = reinterpret_cast<__cxa_exception*>(dependentExceptionHeader->primaryException) - 1;
|
||||
_LIBCXXABI_TRACE_STATETAB("exceptionObject 0x%p is a dependent, primary 0x%p\n",
|
||||
reinterpret_cast<void*>(exceptionObject),
|
||||
reinterpret_cast<void*>(&exceptionHeader->unwindHeader));
|
||||
exceptionObject = &exceptionHeader->unwindHeader;
|
||||
} else {
|
||||
_LIBCXXABI_TRACE_STATETAB("exceptionObject %p is NOT a dependent\n", reinterpret_cast<void*>(exceptionObject));
|
||||
exceptionHeader = reinterpret_cast<__cxa_exception*>(exceptionObject + 1) - 1;
|
||||
}
|
||||
|
||||
void* thrownObject = reinterpret_cast<void*>(exceptionObject + 1);
|
||||
std::type_info* throwTypeInfo = exceptionHeader->exceptionType;
|
||||
|
||||
// Get the type info for the thrown type and this catch clause and
|
||||
// see if the catch caluse can catch that type.
|
||||
|
||||
__cxxabiv1::__shim_type_info* catchType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(catchTypeInfo);
|
||||
__cxxabiv1::__shim_type_info* throwType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(throwTypeInfo);
|
||||
_LIBCXXABI_TRACE_STATETAB("UnwindException=%p, thrownObject=%p, throwTypeInfo=%p(%s), catchTypeInfo=%p(%s)\n",
|
||||
reinterpret_cast<void*>(exceptionObject), thrownObject, reinterpret_cast<void*>(throwType),
|
||||
throwType->name(), reinterpret_cast<void*>(catchType), catchType->name());
|
||||
if (catchType->can_catch(throwType, thrownObject)) {
|
||||
exceptionHeader->adjustedPtr = thrownObject;
|
||||
obj = thrownObject;
|
||||
_LIBCXXABI_TRACE_STATETAB("Match found for thrownObject=%p\n", thrownObject);
|
||||
return true;
|
||||
}
|
||||
_LIBCXXABI_TRACE_STATETAB0("No match\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// __xlc_throw_badexception
|
||||
// This function is for xlclang++. It allocates and throws a bad_exception.
|
||||
// During unwinding for this bad_exception, the previous exception which is
|
||||
// not matching the throw spec will be cleaned up. Thus having the same
|
||||
// effect as replace the top most exception (which is bad) with a bad_exception.
|
||||
_LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() {
|
||||
_LIBCXXABI_TRACE_STATETAB("Entering function: %s\n\n", __func__);
|
||||
void* newexception = new (__cxa_allocate_exception(sizeof(std::bad_exception))) std::bad_exception;
|
||||
__cxa_throw(newexception, const_cast<std::type_info*>(&typeid(std::bad_exception)), 0);
|
||||
}
|
||||
|
||||
// skip_non_cxx_eh_aware_frames
|
||||
// This function skips non-C++ EH aware stack frames by unwinding from the
|
||||
// stack frame pointed by 'Sp' and returns the first C++ EH aware stack frame
|
||||
// found. 'Pc' is an instruction address inside the function that owns the
|
||||
// stack frame pointed to by 'Sp'.
|
||||
static uintptr_t* skip_non_cxx_eh_aware_frames(uint32_t* Pc, uintptr_t* Sp) {
|
||||
uint32_t* currentPc = Pc;
|
||||
uintptr_t* currentStack = Sp;
|
||||
|
||||
// Loop until a C++ EH aware frame is found or the return address is 0,
|
||||
// which is the return address of the startup function '__start'.
|
||||
while (currentPc != 0) {
|
||||
uint32_t* p = currentPc;
|
||||
|
||||
// Keep looking forward until a word of 0 is found. The traceback
|
||||
// table starts at the following word.
|
||||
while (*p)
|
||||
++p;
|
||||
tbtable* TBTable = reinterpret_cast<tbtable*>(p + 1);
|
||||
|
||||
// A stack frame with a C++ state table is C++ EH aware.
|
||||
if (TBTable->tb.lang == TB_CPLUSPLUS && TBTable->tb.has_ctl)
|
||||
return currentStack;
|
||||
|
||||
// Move up one stack frame.
|
||||
currentStack = reinterpret_cast<uintptr_t*>(currentStack[0]);
|
||||
// Get the value of the LR (saved, prior to incrementing the SP, by the
|
||||
// prolog of the function just inspected) from the frame.
|
||||
currentPc = reinterpret_cast<uint32_t*>(currentStack[2]);
|
||||
}
|
||||
// This should not happen.
|
||||
_LIBCXXABI_TRACE_STATETAB0("skip_non_cxx_eh_aware_frames() reached the end of stack frames, aborting\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
// __xlc_exception_handle
|
||||
// This function is for xlclang++. It returns the address of the exception
|
||||
// object stored in the reserved field in the stack of the caller of the
|
||||
// function that calls __xlc_exception_handle() (within the link area for the
|
||||
// call to the latter). The address is stored by the personality routine for
|
||||
// xlclang++ compiled code. If __xlc_exception_handle() is called by
|
||||
// non-C++ EH aware functions, their frames are skipped until a C++ EH aware
|
||||
// frame is found.
|
||||
// Note: make sure __xlc_exception_handle() is a non-leaf function. Currently
|
||||
// it calls skip_non_cxx_eh_aware_frames(), which in turn calls abort().
|
||||
_LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() {
|
||||
// Get the SP of this function, i.e., __xlc_exception_handle().
|
||||
uintptr_t* lastStack = reinterpret_cast<uintptr_t*>(__builtin_frame_address(0));
|
||||
// Move one frame up to the frame of the caller of __xlc_exception_handle().
|
||||
lastStack = reinterpret_cast<uintptr_t*>(lastStack[0]);
|
||||
// Get the return address of this function, i.e., __xlc_exception_handle().
|
||||
uint32_t* returnAddress = reinterpret_cast<uint32_t*>(__builtin_return_address(0));
|
||||
|
||||
// Skip non-C++ EH aware frames and get the first C++ EH aware frame.
|
||||
uintptr_t* callerStack = skip_non_cxx_eh_aware_frames(returnAddress, lastStack);
|
||||
|
||||
// Get the SP of the caller of the C++ EH aware caller.
|
||||
callerStack = reinterpret_cast<uintptr_t*>(callerStack[0]);
|
||||
// Retrieve the exception object in the stack slot saved by the personality.
|
||||
uintptr_t exceptionObject = callerStack[3];
|
||||
_LIBCXXABI_TRACE_STATETAB("Handshake: retrieve exceptionObject=%p from stack=%p\n",
|
||||
reinterpret_cast<void*>(exceptionObject), reinterpret_cast<void*>(callerStack));
|
||||
return exceptionObject;
|
||||
}
|
||||
|
||||
// xlclang++ may generate calls to __Deleted_Virtual.
|
||||
_LIBCXXABI_FUNC_VIS void __Deleted_Virtual() { abort(); }
|
||||
|
||||
// __catchThrownException is called during AIX library initialization and
|
||||
// termination to handle exceptions. An implementation is also provided in
|
||||
// libC.a(shrcore.o). This implementation is provided for applications that
|
||||
// link with -lc++ (the xlclang++ or ibm-clang++ link default.)
|
||||
_LIBCXXABI_FUNC_VIS int
|
||||
__catchThrownException(void (*cdfunc)(void), // function which may fail
|
||||
void (*cleanup)(void*), // cleanup function
|
||||
void* cleanuparg, // parameter to cleanup function
|
||||
int action) { // control exception throwing and termination
|
||||
enum Action : int { None = 0, Rethrow = 1, Terminate = 2 };
|
||||
if (!cdfunc)
|
||||
return 0;
|
||||
if (action == Action::Rethrow && !cleanup) {
|
||||
// No cleanup and rethrow is effectively no-op.
|
||||
// Avoid the catch handler when possible to allow exceptions generated
|
||||
// from xlC binaries to flow through.
|
||||
(*cdfunc)();
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
(*cdfunc)();
|
||||
} catch (...) {
|
||||
if (action == Action::Terminate)
|
||||
std::terminate();
|
||||
if (cleanup)
|
||||
(*cleanup)(cleanuparg);
|
||||
if (action == Action::Rethrow)
|
||||
throw;
|
||||
assert(action == Action::None);
|
||||
return -1; // FAILED
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
} // __cxxabiv1
|
||||
45
lib/libtsan/interception/interception_aix.cpp
vendored
45
lib/libtsan/interception/interception_aix.cpp
vendored
|
|
@ -1,45 +0,0 @@
|
|||
//===-- interception_aix.cpp ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// AIX-specific interception methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "interception.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
|
||||
#if SANITIZER_AIX
|
||||
|
||||
# include <dlfcn.h> // for dlsym()
|
||||
|
||||
namespace __interception {
|
||||
|
||||
static void *GetFuncAddr(const char *name, uptr wrapper_addr) {
|
||||
// AIX dlsym can only defect the functions that are exported, so
|
||||
// on AIX, we can not intercept some basic functions like memcpy.
|
||||
// FIXME: if we are going to ship dynamic asan library, we may need to search
|
||||
// all the loaded modules with RTLD_DEFAULT if RTLD_NEXT failed.
|
||||
void *addr = dlsym(RTLD_NEXT, name);
|
||||
|
||||
// In case `name' is not loaded, dlsym ends up finding the actual wrapper.
|
||||
// We don't want to intercept the wrapper and have it point to itself.
|
||||
if ((uptr)addr == wrapper_addr)
|
||||
addr = nullptr;
|
||||
return addr;
|
||||
}
|
||||
|
||||
bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
|
||||
uptr wrapper) {
|
||||
void *addr = GetFuncAddr(name, wrapper);
|
||||
*ptr_to_real = (uptr)addr;
|
||||
return addr && (func == wrapper);
|
||||
}
|
||||
|
||||
} // namespace __interception
|
||||
#endif // SANITIZER_AIX
|
||||
36
lib/libtsan/interception/interception_aix.h
vendored
36
lib/libtsan/interception/interception_aix.h
vendored
|
|
@ -1,36 +0,0 @@
|
|||
//===-- interception_aix.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// AIX-specific interception methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if SANITIZER_AIX
|
||||
|
||||
# if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
|
||||
# error \
|
||||
"interception_aix.h should be included from interception library only"
|
||||
# endif
|
||||
|
||||
# ifndef INTERCEPTION_AIX_H
|
||||
# define INTERCEPTION_AIX_H
|
||||
|
||||
namespace __interception {
|
||||
bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
|
||||
uptr wrapper);
|
||||
} // namespace __interception
|
||||
|
||||
# define INTERCEPT_FUNCTION_AIX(func) \
|
||||
::__interception::InterceptFunction( \
|
||||
#func, (::__interception::uptr *)&REAL(func), \
|
||||
(::__interception::uptr) & (func), \
|
||||
(::__interception::uptr) & WRAP(func))
|
||||
|
||||
# endif // INTERCEPTION_AIX_H
|
||||
#endif // SANITIZER_AIX
|
||||
63
lib/libunwind/src/Unwind_AIXExtras.cpp
vendored
63
lib/libunwind/src/Unwind_AIXExtras.cpp
vendored
|
|
@ -1,63 +0,0 @@
|
|||
//===--------------------- Unwind_AIXExtras.cpp -------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This file is only used for AIX.
|
||||
#if defined(_AIX)
|
||||
|
||||
#include "config.h"
|
||||
#include "libunwind_ext.h"
|
||||
#include <sys/debug.h>
|
||||
|
||||
namespace libunwind {
|
||||
// getFuncNameFromTBTable
|
||||
// Get the function name from its traceback table.
|
||||
char *getFuncNameFromTBTable(uintptr_t Pc, uint16_t &NameLen,
|
||||
unw_word_t *Offset) {
|
||||
uint32_t *p = reinterpret_cast<uint32_t *>(Pc);
|
||||
*Offset = 0;
|
||||
|
||||
// Keep looking forward until a word of 0 is found. The traceback
|
||||
// table starts at the following word.
|
||||
while (*p)
|
||||
p++;
|
||||
tbtable *TBTable = reinterpret_cast<tbtable *>(p + 1);
|
||||
|
||||
if (!TBTable->tb.name_present)
|
||||
return NULL;
|
||||
|
||||
// Get to the name of the function.
|
||||
p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);
|
||||
|
||||
// Skip field parminfo if it exists.
|
||||
if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
|
||||
p++;
|
||||
|
||||
// If the tb_offset field exists, get the offset from the start of
|
||||
// the function to pc. Skip the field.
|
||||
if (TBTable->tb.has_tboff) {
|
||||
unw_word_t StartIp =
|
||||
reinterpret_cast<uintptr_t>(TBTable) - *p - sizeof(uint32_t);
|
||||
*Offset = Pc - StartIp;
|
||||
p++;
|
||||
}
|
||||
|
||||
// Skip field hand_mask if it exists.
|
||||
if (TBTable->tb.int_hndl)
|
||||
p++;
|
||||
|
||||
// Skip fields ctl_info and ctl_info_disp if they exist.
|
||||
if (TBTable->tb.has_ctl) {
|
||||
p += 1 + *p;
|
||||
}
|
||||
|
||||
NameLen = *(reinterpret_cast<uint16_t *>(p));
|
||||
return reinterpret_cast<char *>(p) + sizeof(uint16_t);
|
||||
}
|
||||
} // namespace libunwind
|
||||
#endif // defined(_AIX)
|
||||
|
|
@ -24,7 +24,6 @@ pub const Os = struct {
|
|||
hermit,
|
||||
managarm,
|
||||
|
||||
aix,
|
||||
haiku,
|
||||
hurd,
|
||||
illumos,
|
||||
|
|
@ -32,7 +31,6 @@ pub const Os = struct {
|
|||
plan9,
|
||||
rtems,
|
||||
serenity,
|
||||
zos,
|
||||
|
||||
dragonfly,
|
||||
freebsd,
|
||||
|
|
@ -174,9 +172,7 @@ pub const Os = struct {
|
|||
.fuchsia,
|
||||
.hermit,
|
||||
|
||||
.aix,
|
||||
.rtems,
|
||||
.zos,
|
||||
|
||||
.dragonfly,
|
||||
.freebsd,
|
||||
|
|
@ -418,12 +414,6 @@ pub const Os = struct {
|
|||
},
|
||||
},
|
||||
|
||||
.aix => .{
|
||||
.semver = .{
|
||||
.min = .{ .major = 7, .minor = 2, .patch = 5 },
|
||||
.max = .{ .major = 7, .minor = 3, .patch = 3 },
|
||||
},
|
||||
},
|
||||
.hurd => .{
|
||||
.hurd = .{
|
||||
.range = .{
|
||||
|
|
@ -494,12 +484,6 @@ pub const Os = struct {
|
|||
.max = .{ .major = 6, .minor = 1, .patch = 0 },
|
||||
},
|
||||
},
|
||||
.zos => .{
|
||||
.semver = .{
|
||||
.min = .{ .major = 2, .minor = 5, .patch = 0 },
|
||||
.max = .{ .major = 3, .minor = 1, .patch = 0 },
|
||||
},
|
||||
},
|
||||
|
||||
.dragonfly => .{
|
||||
.semver = .{
|
||||
|
|
@ -825,7 +809,6 @@ pub const Abi = enum {
|
|||
=> .eabi,
|
||||
else => .none,
|
||||
},
|
||||
.aix => if (arch == .powerpc) .eabihf else .none,
|
||||
.haiku => switch (arch) {
|
||||
.arm,
|
||||
.powerpc,
|
||||
|
|
@ -917,7 +900,6 @@ pub const Abi = enum {
|
|||
.managarm,
|
||||
.plan9,
|
||||
.serenity,
|
||||
.zos,
|
||||
.dragonfly,
|
||||
.driverkit,
|
||||
.macos,
|
||||
|
|
@ -1006,8 +988,6 @@ pub const ObjectFormat = enum {
|
|||
coff,
|
||||
/// The Executable and Linkable Format used by many Unixes.
|
||||
elf,
|
||||
/// The Generalized Object File Format used by z/OS.
|
||||
goff,
|
||||
/// The Intel HEX format for storing binary code in ASCII text.
|
||||
hex,
|
||||
/// The Mach object format used by macOS and other Apple platforms.
|
||||
|
|
@ -1020,8 +1000,6 @@ pub const ObjectFormat = enum {
|
|||
spirv,
|
||||
/// The WebAssembly binary format.
|
||||
wasm,
|
||||
/// The eXtended Common Object File Format used by AIX.
|
||||
xcoff,
|
||||
|
||||
// LLVM tags deliberately omitted:
|
||||
// - dxcontainer
|
||||
|
|
@ -1030,7 +1008,7 @@ pub const ObjectFormat = enum {
|
|||
return switch (of) {
|
||||
.c => ".c",
|
||||
.coff => ".obj",
|
||||
.elf, .goff, .macho, .wasm, .xcoff => ".o",
|
||||
.elf, .macho, .wasm => ".o",
|
||||
.hex => ".ihex",
|
||||
.plan9 => arch.plan9Ext(),
|
||||
.raw => ".bin",
|
||||
|
|
@ -1040,11 +1018,9 @@ pub const ObjectFormat = enum {
|
|||
|
||||
pub fn default(os_tag: Os.Tag, arch: Cpu.Arch) ObjectFormat {
|
||||
return switch (os_tag) {
|
||||
.aix => .xcoff,
|
||||
.driverkit, .ios, .macos, .tvos, .visionos, .watchos => .macho,
|
||||
.plan9 => .plan9,
|
||||
.uefi, .windows => .coff,
|
||||
.zos => .goff,
|
||||
else => switch (arch) {
|
||||
.spirv32, .spirv64 => .spirv,
|
||||
.wasm32, .wasm64 => .wasm,
|
||||
|
|
@ -2030,10 +2006,7 @@ pub const Cpu = struct {
|
|||
.riscv32, .riscv32be => &riscv.cpu.baseline_rv32,
|
||||
.riscv64, .riscv64be => &riscv.cpu.baseline_rv64,
|
||||
// gcc/clang do not have a generic s390x model.
|
||||
.s390x => switch (os.tag) {
|
||||
.zos => &s390x.cpu.arch10,
|
||||
else => &s390x.cpu.arch8,
|
||||
},
|
||||
.s390x => &s390x.cpu.arch8,
|
||||
.sparc => &sparc.cpu.v9, // glibc does not work with 'plain' v8.
|
||||
.x86 => &x86.cpu.pentium4,
|
||||
.x86_64 => switch (os.tag) {
|
||||
|
|
@ -2162,7 +2135,6 @@ pub inline fn isWasiLibC(target: *const Target) bool {
|
|||
/// syscall interface, for example.
|
||||
pub fn requiresLibC(target: *const Target) bool {
|
||||
return switch (target.os.tag) {
|
||||
.aix,
|
||||
.illumos,
|
||||
.driverkit,
|
||||
.macos,
|
||||
|
|
@ -2189,7 +2161,6 @@ pub fn requiresLibC(target: *const Target) bool {
|
|||
.fuchsia,
|
||||
.managarm,
|
||||
.ps3,
|
||||
.zos,
|
||||
.rtems,
|
||||
.cuda,
|
||||
.nvcl,
|
||||
|
|
@ -2347,10 +2318,8 @@ pub const DynamicLinker = struct {
|
|||
.hermit,
|
||||
.managarm, // Needs to be double-checked.
|
||||
|
||||
.aix,
|
||||
.plan9,
|
||||
.rtems,
|
||||
.zos,
|
||||
|
||||
.uefi,
|
||||
.windows,
|
||||
|
|
@ -2759,10 +2728,8 @@ pub const DynamicLinker = struct {
|
|||
.contiki,
|
||||
.hermit,
|
||||
|
||||
.aix,
|
||||
.plan9,
|
||||
.rtems,
|
||||
.zos,
|
||||
|
||||
.uefi,
|
||||
.windows,
|
||||
|
|
@ -2916,7 +2883,7 @@ pub fn stackAlignment(target: *const Target) u16 {
|
|||
// can't handle that level of nuance yet.
|
||||
.powerpc64,
|
||||
.powerpc64le,
|
||||
=> if (target.os.tag == .linux or target.os.tag == .aix) return 16,
|
||||
=> if (target.os.tag == .linux) return 16,
|
||||
.riscv32,
|
||||
.riscv32be,
|
||||
.riscv64,
|
||||
|
|
@ -3112,7 +3079,6 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
|
|||
.fuchsia,
|
||||
.hermit,
|
||||
|
||||
.aix,
|
||||
.haiku,
|
||||
.hurd,
|
||||
.illumos,
|
||||
|
|
@ -3120,7 +3086,6 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
|
|||
.plan9,
|
||||
.rtems,
|
||||
.serenity,
|
||||
.zos,
|
||||
|
||||
.freebsd,
|
||||
.dragonfly,
|
||||
|
|
@ -3175,7 +3140,7 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
|
|||
.muslx32,
|
||||
=> return 64,
|
||||
else => switch (target.os.tag) {
|
||||
.aix, .freebsd, .netbsd, .openbsd => return 64,
|
||||
.freebsd, .netbsd, .openbsd => return 64,
|
||||
else => return 128,
|
||||
},
|
||||
},
|
||||
|
|
@ -3191,7 +3156,7 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
|
|||
.muslx32,
|
||||
=> return 64,
|
||||
else => switch (target.os.tag) {
|
||||
.aix, .freebsd, .openbsd => return 64,
|
||||
.freebsd, .openbsd => return 64,
|
||||
else => return 128,
|
||||
},
|
||||
},
|
||||
|
|
@ -3361,13 +3326,6 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 {
|
|||
.int, .uint, .long, .ulong => return 2,
|
||||
else => {},
|
||||
},
|
||||
.powerpc, .powerpcle, .powerpc64, .powerpc64le => switch (target.os.tag) {
|
||||
.aix => switch (c_type) {
|
||||
.double, .longdouble => return 4,
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.wasm32, .wasm64 => switch (target.os.tag) {
|
||||
.emscripten => switch (c_type) {
|
||||
.longdouble => return 8,
|
||||
|
|
@ -3666,10 +3624,7 @@ pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention
|
|||
else
|
||||
.{ .powerpc64_elf = .{} },
|
||||
.powerpc64le => .{ .powerpc64_elf_v2 = .{} },
|
||||
.powerpc, .powerpcle => switch (target.os.tag) {
|
||||
.aix => .{ .powerpc_aix = .{} },
|
||||
else => .{ .powerpc_sysv = .{} },
|
||||
},
|
||||
.powerpc, .powerpcle => .{ .powerpc_sysv = .{} },
|
||||
.wasm32, .wasm64 => .{ .wasm_mvp = .{} },
|
||||
.arc, .arceb => .{ .arc_sysv = .{} },
|
||||
.avr => .avr_gnu,
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ const CpuModel = std.Target.Cpu.Model;
|
|||
pub const Feature = enum {
|
||||
@"64bit",
|
||||
@"64bitregs",
|
||||
aix,
|
||||
aix_shared_lib_tls_model_opt,
|
||||
aix_small_local_dynamic_tls,
|
||||
aix_small_local_exec_tls,
|
||||
allow_unaligned_fp_access,
|
||||
altivec,
|
||||
booke,
|
||||
|
|
@ -61,7 +57,6 @@ pub const Feature = enum {
|
|||
longcall,
|
||||
mfocrf,
|
||||
mma,
|
||||
modern_aix_as,
|
||||
msync,
|
||||
paired_vector_memops,
|
||||
partword_atomics,
|
||||
|
|
@ -110,26 +105,6 @@ pub const all_features = blk: {
|
|||
.description = "Enable 64-bit registers usage for ppc32 [beta]",
|
||||
.dependencies = featureSet(&[_]Feature{}),
|
||||
};
|
||||
result[@intFromEnum(Feature.aix)] = .{
|
||||
.llvm_name = "aix",
|
||||
.description = "AIX OS",
|
||||
.dependencies = featureSet(&[_]Feature{}),
|
||||
};
|
||||
result[@intFromEnum(Feature.aix_shared_lib_tls_model_opt)] = .{
|
||||
.llvm_name = "aix-shared-lib-tls-model-opt",
|
||||
.description = "Tune TLS model at function level in shared library loaded with the main program (for 64-bit AIX only)",
|
||||
.dependencies = featureSet(&[_]Feature{}),
|
||||
};
|
||||
result[@intFromEnum(Feature.aix_small_local_dynamic_tls)] = .{
|
||||
.llvm_name = "aix-small-local-dynamic-tls",
|
||||
.description = "Produce a faster local-dynamic TLS sequence for this function for 64-bit AIX",
|
||||
.dependencies = featureSet(&[_]Feature{}),
|
||||
};
|
||||
result[@intFromEnum(Feature.aix_small_local_exec_tls)] = .{
|
||||
.llvm_name = "aix-small-local-exec-tls",
|
||||
.description = "Produce a TOC-free local-exec TLS sequence for this function for 64-bit AIX",
|
||||
.dependencies = featureSet(&[_]Feature{}),
|
||||
};
|
||||
result[@intFromEnum(Feature.allow_unaligned_fp_access)] = .{
|
||||
.llvm_name = "allow-unaligned-fp-access",
|
||||
.description = "CPU does not trap on unaligned FP access",
|
||||
|
|
@ -446,11 +421,6 @@ pub const all_features = blk: {
|
|||
.power9_altivec,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.modern_aix_as)] = .{
|
||||
.llvm_name = "modern-aix-as",
|
||||
.description = "AIX system assembler is modern enough to support new mnes",
|
||||
.dependencies = featureSet(&[_]Feature{}),
|
||||
};
|
||||
result[@intFromEnum(Feature.msync)] = .{
|
||||
.llvm_name = "msync",
|
||||
.description = "Has only the msync instruction instead of sync",
|
||||
|
|
|
|||
|
|
@ -1031,10 +1031,7 @@ pub const VaList = switch (builtin.cpu.arch) {
|
|||
.alpha => VaListAlpha,
|
||||
.arm, .armeb, .thumb, .thumbeb => VaListArm,
|
||||
.hexagon => if (builtin.target.abi.isMusl()) VaListHexagon else *u8,
|
||||
.powerpc, .powerpcle => switch (builtin.os.tag) {
|
||||
.aix => *u8,
|
||||
else => VaListPowerPc,
|
||||
},
|
||||
.powerpc, .powerpcle => VaListPowerPc,
|
||||
.s390x => VaListS390x,
|
||||
.sh, .sheb => VaListSh, // This is wrong for `sh_renesas`: https://github.com/ziglang/zig/issues/24692#issuecomment-3150779829
|
||||
.x86_64 => switch (builtin.os.tag) {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ else switch (std.Target.ObjectFormat.default(native_os, native_arch)) {
|
|||
else => @import("debug/SelfInfo/Elf.zig"),
|
||||
},
|
||||
.macho => @import("debug/SelfInfo/MachO.zig"),
|
||||
.goff, .plan9, .spirv, .wasm, .xcoff => void,
|
||||
.plan9, .spirv, .wasm => void,
|
||||
.c, .hex, .raw => unreachable,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
|
|||
},
|
||||
.Obj => return std.fmt.allocPrint(allocator, "{s}.obj", .{root_name}),
|
||||
},
|
||||
.elf, .goff, .xcoff => switch (options.output_mode) {
|
||||
.elf => switch (options.output_mode) {
|
||||
.Exe => return allocator.dupe(u8, root_name),
|
||||
.Lib => {
|
||||
switch (options.link_mode orelse .static) {
|
||||
|
|
|
|||
10
lib/zig.h
10
lib/zig.h
|
|
@ -87,9 +87,7 @@
|
|||
#define zig_big_endian 1
|
||||
#endif
|
||||
|
||||
#if defined(_AIX)
|
||||
#define zig_aix
|
||||
#elif defined(__MACH__)
|
||||
#if defined(__MACH__)
|
||||
#define zig_darwin
|
||||
#elif defined(__DragonFly__)
|
||||
#define zig_dragonfly
|
||||
|
|
@ -119,20 +117,14 @@
|
|||
#define zig_wasi
|
||||
#elif defined(_WIN32)
|
||||
#define zig_windows
|
||||
#elif defined(__MVS__)
|
||||
#define zig_zos
|
||||
#endif
|
||||
|
||||
#if defined(zig_windows)
|
||||
#define zig_coff
|
||||
#elif defined(__ELF__)
|
||||
#define zig_elf
|
||||
#elif defined(zig_zos)
|
||||
#define zig_goff
|
||||
#elif defined(zig_darwin)
|
||||
#define zig_macho
|
||||
#elif defined(zig_aix)
|
||||
#define zig_xcoff
|
||||
#endif
|
||||
|
||||
#define zig_concat(lhs, rhs) lhs##rhs
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ pub fn resolve(options: Options) ResolveError!Config {
|
|||
if (root_strip and !options.any_non_stripped) break :b .strip;
|
||||
if (options.debug_format) |x| break :b x;
|
||||
break :b switch (target.ofmt) {
|
||||
.elf, .goff, .macho, .wasm, .xcoff => .{ .dwarf = .@"32" },
|
||||
.elf, .macho, .wasm => .{ .dwarf = .@"32" },
|
||||
.coff => .code_view,
|
||||
.c => switch (target.os.tag) {
|
||||
.windows, .uefi => .code_view,
|
||||
|
|
|
|||
|
|
@ -179,9 +179,6 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8
|
|||
try llvm_triple.append('-');
|
||||
|
||||
try llvm_triple.appendSlice(switch (target.os.tag) {
|
||||
.aix,
|
||||
.zos,
|
||||
=> "ibm",
|
||||
.driverkit,
|
||||
.ios,
|
||||
.macos,
|
||||
|
|
@ -214,10 +211,8 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8
|
|||
.openbsd => "openbsd",
|
||||
.illumos => "solaris",
|
||||
.windows, .uefi => "windows",
|
||||
.zos => "zos",
|
||||
.haiku => "haiku",
|
||||
.rtems => "rtems",
|
||||
.aix => "aix",
|
||||
.cuda => "cuda",
|
||||
.nvcl => "nvcl",
|
||||
.amdhsa => "amdhsa",
|
||||
|
|
@ -382,13 +377,9 @@ pub fn dataLayout(target: *const std.Target) []const u8 {
|
|||
else => "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
||||
},
|
||||
.m68k => "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16",
|
||||
.powerpc => if (target.os.tag == .aix)
|
||||
"E-m:a-p:32:32-Fi32-i64:64-n32"
|
||||
else
|
||||
"E-m:e-p:32:32-Fn32-i64:64-n32",
|
||||
.powerpc => "E-m:e-p:32:32-Fn32-i64:64-n32",
|
||||
.powerpcle => "e-m:e-p:32:32-Fn32-i64:64-n32",
|
||||
.powerpc64 => switch (target.os.tag) {
|
||||
.aix => "E-m:a-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512",
|
||||
.linux => if (target.abi.isMusl())
|
||||
"E-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512"
|
||||
else
|
||||
|
|
@ -425,10 +416,7 @@ pub fn dataLayout(target: *const std.Target) []const u8 {
|
|||
"E-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
|
||||
.sparc => "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64",
|
||||
.sparc64 => "E-m:e-i64:64-i128:128-n32:64-S128",
|
||||
.s390x => if (target.os.tag == .zos)
|
||||
"E-m:l-p1:32:32-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
|
||||
else
|
||||
"E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64",
|
||||
.s390x => "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64",
|
||||
.x86 => if (target.os.tag == .windows or target.os.tag == .uefi) switch (target.abi) {
|
||||
.cygnus => "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32",
|
||||
.gnu => if (target.ofmt == .coff)
|
||||
|
|
@ -517,7 +505,7 @@ fn codeModel(model: std.builtin.CodeModel, target: *const std.Target) CodeModel
|
|||
.extreme, .large => .large,
|
||||
.kernel => .kernel,
|
||||
.medany => if (target.cpu.arch.isRISCV()) .medium else .large,
|
||||
.medium => if (target.os.tag == .aix) .large else .medium,
|
||||
.medium => .medium,
|
||||
.medmid => .medium,
|
||||
.normal, .medlow, .small => .small,
|
||||
.tiny => .tiny,
|
||||
|
|
@ -12828,12 +12816,6 @@ fn backendSupportsF128(target: *const std.Target) bool {
|
|||
// https://github.com/llvm/llvm-project/issues/41838
|
||||
.sparc,
|
||||
=> false,
|
||||
// https://github.com/llvm/llvm-project/issues/101545
|
||||
.powerpc,
|
||||
.powerpcle,
|
||||
.powerpc64,
|
||||
.powerpc64le,
|
||||
=> target.os.tag != .aix,
|
||||
.arm,
|
||||
.armeb,
|
||||
.thumb,
|
||||
|
|
|
|||
|
|
@ -104,8 +104,6 @@ pub const Env = enum {
|
|||
.wasm_linker,
|
||||
.spirv_linker,
|
||||
.plan9_linker,
|
||||
.goff_linker,
|
||||
.xcoff_linker,
|
||||
=> true,
|
||||
.cc_command,
|
||||
.translate_c_command,
|
||||
|
|
@ -293,8 +291,6 @@ pub const Feature = enum {
|
|||
wasm_linker,
|
||||
spirv_linker,
|
||||
plan9_linker,
|
||||
goff_linker,
|
||||
xcoff_linker,
|
||||
};
|
||||
|
||||
/// Makes the code following the call to this function unreachable if `feature` is disabled.
|
||||
|
|
|
|||
|
|
@ -79,9 +79,6 @@ const libcxx_base_files = [_][]const u8{
|
|||
"src/stdexcept.cpp",
|
||||
"src/string.cpp",
|
||||
"src/strstream.cpp",
|
||||
"src/support/ibm/mbsnrtowcs.cpp",
|
||||
"src/support/ibm/wcsnrtombs.cpp",
|
||||
"src/support/ibm/xlocale_zos.cpp",
|
||||
"src/support/win32/locale_win32.cpp",
|
||||
"src/support/win32/support.cpp",
|
||||
"src/system_error.cpp",
|
||||
|
|
@ -203,8 +200,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
|
|||
continue;
|
||||
if (std.mem.startsWith(u8, cxx_src, "src/support/win32/") and target.os.tag != .windows)
|
||||
continue;
|
||||
if (std.mem.startsWith(u8, cxx_src, "src/support/ibm/") and target.os.tag != .zos)
|
||||
continue;
|
||||
|
||||
var cflags = std.array_list.Managed([]const u8).init(arena);
|
||||
|
||||
|
|
@ -223,11 +218,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
|
|||
try cflags.append("-fvisibility=hidden");
|
||||
try cflags.append("-fvisibility-inlines-hidden");
|
||||
|
||||
if (target.os.tag == .zos) {
|
||||
try cflags.append("-fno-aligned-allocation");
|
||||
} else {
|
||||
try cflags.append("-faligned-allocation");
|
||||
}
|
||||
|
||||
try cflags.append("-nostdinc++");
|
||||
try cflags.append("-std=c++23");
|
||||
|
|
|
|||
|
|
@ -480,7 +480,6 @@ const sanitizer_symbolizer_sources = [_][]const u8{
|
|||
};
|
||||
|
||||
const interception_sources = [_][]const u8{
|
||||
"interception_aix.cpp",
|
||||
"interception_linux.cpp",
|
||||
"interception_mac.cpp",
|
||||
"interception_win.cpp",
|
||||
|
|
|
|||
|
|
@ -198,6 +198,5 @@ const unwind_src_list = [_][]const u8{
|
|||
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-wasm.c",
|
||||
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersRestore.S",
|
||||
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersSave.S",
|
||||
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind_AIXExtras.cpp",
|
||||
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "gcc_personality_v0.c",
|
||||
};
|
||||
|
|
|
|||
22
src/link.zig
22
src/link.zig
|
|
@ -574,9 +574,9 @@ pub const File = struct {
|
|||
const gpa = comp.gpa;
|
||||
switch (base.tag) {
|
||||
.lld => assert(base.file == null),
|
||||
.elf, .macho, .wasm, .goff, .xcoff => {
|
||||
.elf, .macho, .wasm => {
|
||||
if (base.file != null) return;
|
||||
dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker });
|
||||
dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker });
|
||||
const emit = base.emit;
|
||||
if (base.child_pid) |pid| {
|
||||
if (builtin.os.tag == .windows) {
|
||||
|
|
@ -681,8 +681,8 @@ pub const File = struct {
|
|||
}
|
||||
}
|
||||
},
|
||||
.macho, .wasm, .goff, .xcoff => if (base.file) |f| {
|
||||
dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker });
|
||||
.macho, .wasm => if (base.file) |f| {
|
||||
dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker });
|
||||
f.close();
|
||||
base.file = null;
|
||||
|
||||
|
|
@ -825,7 +825,6 @@ pub const File = struct {
|
|||
switch (base.tag) {
|
||||
.lld => unreachable,
|
||||
.spirv => {},
|
||||
.goff, .xcoff => {},
|
||||
.plan9 => unreachable,
|
||||
.elf2, .coff2 => {},
|
||||
inline else => |tag| {
|
||||
|
|
@ -973,7 +972,6 @@ pub const File = struct {
|
|||
.c => unreachable,
|
||||
.spirv => unreachable,
|
||||
.wasm => unreachable,
|
||||
.goff, .xcoff => unreachable,
|
||||
.plan9 => unreachable,
|
||||
inline else => |tag| {
|
||||
dev.check(tag.devFeature());
|
||||
|
|
@ -996,7 +994,6 @@ pub const File = struct {
|
|||
.c => unreachable,
|
||||
.spirv => unreachable,
|
||||
.wasm => unreachable,
|
||||
.goff, .xcoff => unreachable,
|
||||
.plan9 => unreachable,
|
||||
inline else => |tag| {
|
||||
dev.check(tag.devFeature());
|
||||
|
|
@ -1013,7 +1010,6 @@ pub const File = struct {
|
|||
.c => unreachable,
|
||||
.spirv => unreachable,
|
||||
.wasm => unreachable,
|
||||
.goff, .xcoff => unreachable,
|
||||
.plan9 => unreachable,
|
||||
inline else => |tag| {
|
||||
dev.check(tag.devFeature());
|
||||
|
|
@ -1034,8 +1030,6 @@ pub const File = struct {
|
|||
.plan9 => unreachable,
|
||||
|
||||
.spirv,
|
||||
.goff,
|
||||
.xcoff,
|
||||
=> {},
|
||||
|
||||
inline else => |tag| {
|
||||
|
|
@ -1171,8 +1165,6 @@ pub const File = struct {
|
|||
wasm,
|
||||
spirv,
|
||||
plan9,
|
||||
goff,
|
||||
xcoff,
|
||||
lld,
|
||||
|
||||
pub fn Type(comptime tag: Tag) type {
|
||||
|
|
@ -1184,8 +1176,6 @@ pub const File = struct {
|
|||
.c => C,
|
||||
.wasm => Wasm,
|
||||
.spirv => SpirV,
|
||||
.goff => Goff,
|
||||
.xcoff => Xcoff,
|
||||
.lld => Lld,
|
||||
.plan9 => comptime unreachable,
|
||||
};
|
||||
|
|
@ -1200,8 +1190,6 @@ pub const File = struct {
|
|||
.plan9 => .plan9,
|
||||
.c => .c,
|
||||
.spirv => .spirv,
|
||||
.goff => .goff,
|
||||
.xcoff => .xcoff,
|
||||
.hex => @panic("TODO implement hex object format"),
|
||||
.raw => @panic("TODO implement raw object format"),
|
||||
};
|
||||
|
|
@ -1284,8 +1272,6 @@ pub const File = struct {
|
|||
pub const MachO = @import("link/MachO.zig");
|
||||
pub const SpirV = @import("link/SpirV.zig");
|
||||
pub const Wasm = @import("link/Wasm.zig");
|
||||
pub const Goff = @import("link/Goff.zig");
|
||||
pub const Xcoff = @import("link/Xcoff.zig");
|
||||
pub const Dwarf = @import("link/Dwarf.zig");
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -418,7 +418,6 @@ fn create(
|
|||
.freestanding, .other => .STANDALONE,
|
||||
.netbsd => .NETBSD,
|
||||
.illumos => .SOLARIS,
|
||||
.aix => .AIX,
|
||||
.freebsd, .ps4 => .FREEBSD,
|
||||
.openbsd => .OPENBSD,
|
||||
.cuda => .CUDA,
|
||||
|
|
|
|||
|
|
@ -1,112 +0,0 @@
|
|||
//! Stub linker support for GOFF based on LLVM.
|
||||
|
||||
const Goff = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const log = std.log.scoped(.link);
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const Zcu = @import("../Zcu.zig");
|
||||
const InternPool = @import("../InternPool.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const codegen = @import("../codegen.zig");
|
||||
const link = @import("../link.zig");
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const build_options = @import("build_options");
|
||||
|
||||
base: link.File,
|
||||
|
||||
pub fn createEmpty(
|
||||
arena: Allocator,
|
||||
comp: *Compilation,
|
||||
emit: Path,
|
||||
options: link.File.OpenOptions,
|
||||
) !*Goff {
|
||||
const target = &comp.root_mod.resolved_target.result;
|
||||
const use_lld = build_options.have_llvm and comp.config.use_lld;
|
||||
const use_llvm = comp.config.use_llvm;
|
||||
|
||||
assert(use_llvm); // Caught by Compilation.Config.resolve.
|
||||
assert(!use_lld); // Caught by Compilation.Config.resolve.
|
||||
assert(target.os.tag == .zos); // Caught by Compilation.Config.resolve.
|
||||
|
||||
const goff = try arena.create(Goff);
|
||||
goff.* = .{
|
||||
.base = .{
|
||||
.tag = .goff,
|
||||
.comp = comp,
|
||||
.emit = emit,
|
||||
.zcu_object_basename = emit.sub_path,
|
||||
.gc_sections = options.gc_sections orelse false,
|
||||
.print_gc_sections = options.print_gc_sections,
|
||||
.stack_size = options.stack_size orelse 0,
|
||||
.allow_shlib_undefined = options.allow_shlib_undefined orelse false,
|
||||
.file = null,
|
||||
.build_id = options.build_id,
|
||||
},
|
||||
};
|
||||
|
||||
return goff;
|
||||
}
|
||||
|
||||
pub fn open(
|
||||
arena: Allocator,
|
||||
comp: *Compilation,
|
||||
emit: Path,
|
||||
options: link.File.OpenOptions,
|
||||
) !*Goff {
|
||||
const target = &comp.root_mod.resolved_target.result;
|
||||
assert(target.ofmt == .goff);
|
||||
return createEmpty(arena, comp, emit, options);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Goff) void {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
pub fn updateFunc(
|
||||
self: *Goff,
|
||||
pt: Zcu.PerThread,
|
||||
func_index: InternPool.Index,
|
||||
mir: *const codegen.AnyMir,
|
||||
) link.File.UpdateNavError!void {
|
||||
_ = self;
|
||||
_ = pt;
|
||||
_ = func_index;
|
||||
_ = mir;
|
||||
unreachable; // we always use llvm
|
||||
}
|
||||
|
||||
pub fn updateNav(self: *Goff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void {
|
||||
_ = self;
|
||||
_ = pt;
|
||||
_ = nav;
|
||||
unreachable; // we always use llvm
|
||||
}
|
||||
|
||||
pub fn updateExports(
|
||||
self: *Goff,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) !void {
|
||||
_ = self;
|
||||
_ = pt;
|
||||
_ = exported;
|
||||
_ = export_indices;
|
||||
unreachable; // we always use llvm
|
||||
}
|
||||
|
||||
pub fn flush(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .goff)
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
|
||||
_ = self;
|
||||
_ = arena;
|
||||
_ = tid;
|
||||
_ = prog_node;
|
||||
}
|
||||
|
|
@ -348,7 +348,6 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void {
|
|||
object_files.items.ptr,
|
||||
object_files.items.len,
|
||||
switch (target.os.tag) {
|
||||
.aix => .AIXBIG,
|
||||
.windows => .COFF,
|
||||
else => if (target.os.tag.isDarwin()) .DARWIN else .GNU,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,112 +0,0 @@
|
|||
//! Stub linker support for GOFF based on LLVM.
|
||||
|
||||
const Xcoff = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const log = std.log.scoped(.link);
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const Zcu = @import("../Zcu.zig");
|
||||
const InternPool = @import("../InternPool.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const codegen = @import("../codegen.zig");
|
||||
const link = @import("../link.zig");
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const build_options = @import("build_options");
|
||||
|
||||
base: link.File,
|
||||
|
||||
pub fn createEmpty(
|
||||
arena: Allocator,
|
||||
comp: *Compilation,
|
||||
emit: Path,
|
||||
options: link.File.OpenOptions,
|
||||
) !*Xcoff {
|
||||
const target = &comp.root_mod.resolved_target.result;
|
||||
const use_lld = build_options.have_llvm and comp.config.use_lld;
|
||||
const use_llvm = comp.config.use_llvm;
|
||||
|
||||
assert(use_llvm); // Caught by Compilation.Config.resolve.
|
||||
assert(!use_lld); // Caught by Compilation.Config.resolve.
|
||||
assert(target.os.tag == .aix); // Caught by Compilation.Config.resolve.
|
||||
|
||||
const xcoff = try arena.create(Xcoff);
|
||||
xcoff.* = .{
|
||||
.base = .{
|
||||
.tag = .xcoff,
|
||||
.comp = comp,
|
||||
.emit = emit,
|
||||
.zcu_object_basename = emit.sub_path,
|
||||
.gc_sections = options.gc_sections orelse false,
|
||||
.print_gc_sections = options.print_gc_sections,
|
||||
.stack_size = options.stack_size orelse 0,
|
||||
.allow_shlib_undefined = options.allow_shlib_undefined orelse false,
|
||||
.file = null,
|
||||
.build_id = options.build_id,
|
||||
},
|
||||
};
|
||||
|
||||
return xcoff;
|
||||
}
|
||||
|
||||
pub fn open(
|
||||
arena: Allocator,
|
||||
comp: *Compilation,
|
||||
emit: Path,
|
||||
options: link.File.OpenOptions,
|
||||
) !*Xcoff {
|
||||
const target = &comp.root_mod.resolved_target.result;
|
||||
assert(target.ofmt == .xcoff);
|
||||
return createEmpty(arena, comp, emit, options);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Xcoff) void {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
pub fn updateFunc(
|
||||
self: *Xcoff,
|
||||
pt: Zcu.PerThread,
|
||||
func_index: InternPool.Index,
|
||||
mir: *const codegen.AnyMir,
|
||||
) link.File.UpdateNavError!void {
|
||||
_ = self;
|
||||
_ = pt;
|
||||
_ = func_index;
|
||||
_ = mir;
|
||||
unreachable; // we always use llvm
|
||||
}
|
||||
|
||||
pub fn updateNav(self: *Xcoff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void {
|
||||
_ = self;
|
||||
_ = pt;
|
||||
_ = nav;
|
||||
unreachable; // we always use llvm
|
||||
}
|
||||
|
||||
pub fn updateExports(
|
||||
self: *Xcoff,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) !void {
|
||||
_ = self;
|
||||
_ = pt;
|
||||
_ = exported;
|
||||
_ = export_indices;
|
||||
unreachable; // we always use llvm
|
||||
}
|
||||
|
||||
pub fn flush(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .xcoff)
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
|
||||
_ = self;
|
||||
_ = arena;
|
||||
_ = tid;
|
||||
_ = prog_node;
|
||||
}
|
||||
|
|
@ -155,13 +155,11 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
|
|||
|
||||
.coff,
|
||||
.elf,
|
||||
.goff,
|
||||
.hex,
|
||||
.macho,
|
||||
.spirv,
|
||||
.raw,
|
||||
.wasm,
|
||||
.xcoff,
|
||||
=> {},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -175,7 +175,6 @@ const targets = [_]std.Target.Query{
|
|||
.{ .cpu_arch = .nvptx64, .os_tag = .cuda, .abi = .none },
|
||||
.{ .cpu_arch = .nvptx64, .os_tag = .nvcl, .abi = .none },
|
||||
|
||||
.{ .cpu_arch = .powerpc, .os_tag = .aix, .abi = .eabihf },
|
||||
.{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabi },
|
||||
.{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabihf },
|
||||
.{ .cpu_arch = .powerpc, .os_tag = .haiku, .abi = .eabi },
|
||||
|
|
@ -196,7 +195,6 @@ const targets = [_]std.Target.Query{
|
|||
.{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabi },
|
||||
.{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabihf },
|
||||
|
||||
.{ .cpu_arch = .powerpc64, .os_tag = .aix, .abi = .none },
|
||||
.{ .cpu_arch = .powerpc64, .os_tag = .freebsd, .abi = .none },
|
||||
.{ .cpu_arch = .powerpc64, .os_tag = .freestanding, .abi = .none },
|
||||
.{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .gnu },
|
||||
|
|
@ -239,7 +237,6 @@ const targets = [_]std.Target.Query{
|
|||
.{ .cpu_arch = .s390x, .os_tag = .freestanding, .abi = .none },
|
||||
.{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .gnu },
|
||||
.{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .none },
|
||||
// .{ .cpu_arch = .s390x, .os_tag = .zos, .abi = .none },
|
||||
|
||||
.{ .cpu_arch = .sparc, .os_tag = .freestanding, .abi = .none },
|
||||
.{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .gnu },
|
||||
|
|
|
|||
|
|
@ -1051,6 +1051,28 @@ const targets = [_]ArchTarget{
|
|||
.name = "PowerPC",
|
||||
.td_name = "PPC",
|
||||
},
|
||||
.feature_overrides = &.{
|
||||
.{
|
||||
.llvm_name = "aix",
|
||||
.omit = true,
|
||||
},
|
||||
.{
|
||||
.llvm_name = "aix-shared-lib-tls-model-opt",
|
||||
.omit = true,
|
||||
},
|
||||
.{
|
||||
.llvm_name = "aix-small-local-dynamic-tls",
|
||||
.omit = true,
|
||||
},
|
||||
.{
|
||||
.llvm_name = "aix-small-local-exec-tls",
|
||||
.omit = true,
|
||||
},
|
||||
.{
|
||||
.llvm_name = "modern-aix-as",
|
||||
.omit = true,
|
||||
},
|
||||
},
|
||||
.omit_cpus = &.{
|
||||
"ppc32",
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue