remove all IBM AIX and z/OS support

As with Solaris (dba1bf935390ddb0184a4dc72245454de6c06fd2), 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:
Alex Rønne Petersen 2025-10-29 07:32:01 +01:00
parent 6568f0f75b
commit a7119d4269
38 changed files with 47 additions and 1910 deletions

View File

@ -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

View File

@ -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| {

View File

@ -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,

View File

@ -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)) {

View File

@ -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,

View File

@ -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 => {

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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",

View File

@ -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) {

View File

@ -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,
};

View File

@ -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) {

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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.

View File

@ -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("-faligned-allocation");
try cflags.append("-nostdinc++");
try cflags.append("-std=c++23");

View File

@ -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",

View File

@ -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",
};

View File

@ -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");
};

View File

@ -418,7 +418,6 @@ fn create(
.freestanding, .other => .STANDALONE,
.netbsd => .NETBSD,
.illumos => .SOLARIS,
.aix => .AIX,
.freebsd, .ps4 => .FREEBSD,
.openbsd => .OPENBSD,
.cuda => .CUDA,

View File

@ -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;
}

View File

@ -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,
},

View File

@ -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;
}

View File

@ -155,13 +155,11 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
.coff,
.elf,
.goff,
.hex,
.macho,
.spirv,
.raw,
.wasm,
.xcoff,
=> {},
}

View File

@ -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 },

View File

@ -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",
},