From 5b5abb83b36fa10ccdab15ca81cbb9c6f8718a8d Mon Sep 17 00:00:00 2001 From: swcompiler Date: Fri, 30 May 2025 16:49:11 +0800 Subject: [PATCH 1/2] [Sw64] Add Sw64 target support for lld --- lld/ELF/Arch/Sw_64.cpp | 354 ++++++++++++++++++++++++++++++++++ lld/ELF/CMakeLists.txt | 1 + lld/ELF/Config.h | 4 + lld/ELF/Driver.cpp | 15 +- lld/ELF/InputFiles.cpp | 2 + lld/ELF/InputSection.cpp | 23 ++- lld/ELF/Options.td | 19 ++ lld/ELF/Relocations.cpp | 131 ++++++++++++- lld/ELF/Relocations.h | 6 + lld/ELF/ScriptParser.cpp | 1 + lld/ELF/SyntheticSections.cpp | 232 ++++++++++++++++++++++ lld/ELF/SyntheticSections.h | 56 +++++- lld/ELF/Target.cpp | 2 + lld/ELF/Target.h | 1 + lld/ELF/Writer.cpp | 37 +++- 15 files changed, 869 insertions(+), 15 deletions(-) create mode 100644 lld/ELF/Arch/Sw_64.cpp diff --git a/lld/ELF/Arch/Sw_64.cpp b/lld/ELF/Arch/Sw_64.cpp new file mode 100644 index 000000000000..fa3f74adc560 --- /dev/null +++ b/lld/ELF/Arch/Sw_64.cpp @@ -0,0 +1,354 @@ +//===- Sw_64.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 +// +//===----------------------------------------------------------------------===// + +#include "InputFiles.h" +#include "OutputSections.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "Thunks.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::ELF; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace lld; +using namespace lld::elf; + +namespace { +template class Sw_64 final : public TargetInfo { +public: + Sw_64(); + uint32_t calcEFlags() const override; + RelExpr getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const override; + RelType getDynRel(RelType type) const override; + void writePltHeader(uint8_t *buf) const override; + void writePlt(uint8_t *buf, const Symbol &sym, + uint64_t pltEntryAddr) const override; + void relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; + +private: + static inline uint32_t high(uint32_t value){ + return (value >> 16) + (0 != (value & 0x8000)); + } + + static inline void Write16(void *P, uint16_t V){ + return write16(P, V); + } + + static inline void Write32(void *P, uint32_t V){ + return write32(P, V); + } + + static inline void Write64(void *P, uint64_t V){ + return write64(P, V); + } + + static inline uint16_t Read16(void *P){ + return read16(P); + } + + static inline uint32_t Read32(void *P){ + return read32(P); + } + + static inline uint64_t Read64(void *P){ + return read64(P); + } + + static inline uint32_t bit_select32(uint32_t a, uint32_t b, uint32_t mask){ + return (a & ~mask) | (b & mask); + } + + static constexpr int32_t LITUSE_JSR = 3; + static constexpr uintptr_t RA_SHIFT = 21; + static constexpr uintptr_t RB_SHIFT = 16; + static constexpr uintptr_t RC_MASK = 31; + static constexpr uintptr_t RA_MASK = RC_MASK << RA_SHIFT; + static constexpr uintptr_t RB_MASK = RC_MASK << RB_SHIFT; + +}; +} // namespace + +template +Sw_64::Sw_64(){ + defaultCommonPageSize = 0x2000; + defaultMaxPageSize = 0x10000; + defaultImageBase = 0x120000000; + gotRel = R_SW_64_GLOB_DAT; + pltRel = R_SW_64_JMP_SLOT; + relativeRel = R_SW_64_RELATIVE; + symbolicRel = R_SW_64_REFQUAD; + tlsGotRel = R_SW_64_TPREL64; + tlsModuleIndexRel = R_SW_64_DTPMOD64; + tlsOffsetRel = R_SW_64_DTPREL64; + pltEntrySize = 0x4; + pltHeaderSize = 0x24; + + // .got.plt header should be 16 bytes. We only get 8 bytes here. + // A dummy entry will be added when necessary to compensate. + gotPltHeaderEntriesNum = 1; + + // SW dynamic linker treat rela as rel and does not use addend in rela at all, + // so we force to write out the addend to the position relocated. + config->writeAddends = true; +} + +template +uint32_t Sw_64::calcEFlags() const { + return /* sw6a */ 0x4; +} + +template +RelExpr Sw_64::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { + switch(0xff & Type){ + case R_SW_64_NONE: + return R_NONE; + case R_SW_64_LITERAL: + if(S.isFunc() && (LITUSE_JSR << 8) == (Type & 0xff00))return R_SW_PLT_GOT_OFF; + // fallthrough + case R_SW_64_GLOB_DAT: + case R_SW_64_GOTTPREL: + return R_SW_GOT_OFF; + case R_SW_64_TLSGD: + case R_SW_64_TLSLDM: + return R_SW_TLSGD_GOT; + case R_SW_64_GPDISP: + return R_SW_GOT_GP_PC; + case R_SW_64_LITUSE: + case R_SW_64_HINT: + return R_SW_HINT_PC; + case R_SW_64_BRADDR: + case R_SW_64_BRSGP: + case R_SW_64_SREL16: + case R_SW_64_SREL32: + case R_SW_64_SREL64: + return R_PC; + case R_SW_64_GPREL32: + case R_SW_64_GPREL16: + case R_SW_64_GPRELHIGH: + case R_SW_64_GPRELLOW: + return R_SW_GOTREL; + case R_SW_64_REFLONG: + case R_SW_64_REFQUAD: + case R_SW_64_LITERAL_GOT: + return R_ABS; + case R_SW_64_TPREL64: + case R_SW_64_TPRELHI: + case R_SW_64_TPRELLO: + case R_SW_64_TPREL16: + return R_TPREL; + case R_SW_64_DTPRELHI: + case R_SW_64_DTPRELLO: + return R_DTPREL; + default: + error(getErrorLocation(Loc) + "do not know how to handle relocation " + toString(Type)); + return R_NONE; + } +} + + + +template RelType Sw_64::getDynRel(RelType type) const { + return type; +} + +template +void Sw_64::relocate(uint8_t *Loc, const Relocation &rel, + uint64_t Val) const { + RelType Type = rel.type; + switch(0xff & Type){ + case R_SW_64_NONE: + case R_SW_64_LITUSE: + case R_SW_64_LITERAL_GOT: + // This can't be guarded by `literalgot` option, gcc already generates this + // relocations pre-8X. + + // Nothing to do. + break; + case R_SW_64_GPDISP: { + auto Addend = llvm::SignExtend32<24>(Type >> 8); + auto i_hi = Read32(Loc); + auto i_lo = Read32(Loc + Addend); + + auto implicit_addend = ((i_hi & 0xffff) << 16) | (i_lo & 0xffff); + implicit_addend = (implicit_addend ^ 0x80008000) - 0x80008000; + // Addend is for the address of the other instruction, not the displacement. + Val -= Addend; + Val += implicit_addend; + if(static_cast(Val) < INT32_MIN || INT32_MAX < static_cast(Val)){ + error(getErrorLocation(Loc) + toString(Type) + " overflowed: 0x" + Twine::utohexstr(Val)); + } + i_hi = bit_select32(i_hi, high(Val), 0xffff); + i_lo = bit_select32(i_lo, Val, 0xffff); + Write32(Loc, i_hi); + Write32(Loc + Addend, i_lo); + }break; + case R_SW_64_BRSGP: + // TODO: Check .prologue. + // fallthrough + case R_SW_64_BRADDR: + { + auto inst = Read32(Loc); + Val = (Val >> 2) - 1; + Write32(Loc, bit_select32(inst, Val, 0x1fffff)); + }break; + case R_SW_64_HINT: { + Val = (Val >> 2) - 1; + auto inst = bit_select32(Read32(Loc), Val, 0xffff); + Write32(Loc, inst); + }break; + case R_SW_64_SREL16: { + // TODO: Overflow? + auto inst = Read16(Loc); + Write16(Loc, Val + inst); + }break; + case R_SW_64_REFLONG: + case R_SW_64_SREL32: + case R_SW_64_GPREL32: + { + // TODO: Overflow? + auto inst = Read32(Loc); + Write32(Loc, Val + inst); + }break; + case R_SW_64_DTPMOD64: + Val = !config->shared; + // fallthrough + case R_SW_64_REFQUAD: + case R_SW_64_SREL64: + case R_SW_64_TPREL64: + { + // TODO: Overflow? + auto inst = Read64(Loc); + Write64(Loc, Val + inst); + }break; + case R_SW_64_GLOB_DAT: + case R_SW_64_JMP_SLOT: + { + Write64(Loc, Val); + }break; + case R_SW_64_GPRELHIGH: + case R_SW_64_TPRELHI: + case R_SW_64_DTPRELHI: + { + auto inst = Read32(Loc); + Write32(Loc, bit_select32(inst, high(Val), 0xffff)); + }break; + case R_SW_64_LITERAL: { + auto literal_inst = Read32(Loc); + auto hi_addend = llvm::SignExtend32<16>(Type >> 16); + if(0 != hi_addend){ + auto hi_loc = Loc + hi_addend; + auto got_inst = Read32(hi_loc); + // TODO: Check the protocol is correct. + + // Change previous instruction with R_SW_64_LITERAL_GOT to load the high part of GOT. + Write32(hi_loc, bit_select32(got_inst, high(Val), 0xffff)); + // Change the base register of low load to the destination register of the high load. + literal_inst = bit_select32(literal_inst, (got_inst & RA_MASK) >> (RA_SHIFT - RB_SHIFT), RC_MASK << RB_SHIFT); + }else if(static_cast(Val) < INT16_MIN || INT16_MAX < static_cast(Val)){ + error(getErrorLocation(Loc) + toString(Type) + " overflowed: 0x" + Twine::utohexstr(Val)); + } + Write32(Loc, bit_select32(literal_inst, Val, 0xffff)); + }break; + +#define LDIH_GOT(Loc, Type, Val, option) \ + do{ \ + auto inst = Read32(Loc); \ + Val += inst & 0xffff; \ + \ + auto hi_addend = llvm::SignExtend32<16>(Type >> 16); \ + if(0 != hi_addend){ \ + if(config->option){ \ + auto hi_loc = Loc + hi_addend; \ + auto got_inst = Read32(hi_loc); \ + \ + /* Change previous instruction with R_SW_64_TLSREL_GOT to load the high part of GOT. */ \ + Write32(hi_loc, bit_select32(got_inst, high(Val), 0xffff)); \ + /* Change the base register of low load to the destination register of the high load. */ \ + inst = bit_select32(inst, (got_inst & RA_MASK) >> (RA_SHIFT - RB_SHIFT), RC_MASK << RB_SHIFT); \ + }else{ \ + error(getErrorLocation(Loc) + "add `--" #option "` to enable large range relocation " + toString(0xffff & Type)); \ + } \ + }else if(static_cast(Val) < INT16_MIN || INT16_MAX < static_cast(Val)){ \ + error(getErrorLocation(Loc) + toString(0xffff & Type) + " overflowed: 0x" + Twine::utohexstr(Val)); \ + } \ + Write32(Loc, bit_select32(inst, Val, 0xffff)); \ + }while(false) \ + // end of LDIH_GOT + + case R_SW_64_TLSGD: + LDIH_GOT(Loc, Type, Val, sw64_tlsrelgot_tlsgd); + break; + case R_SW_64_TLSLDM: + LDIH_GOT(Loc, Type, Val, sw64_tlsrelgot_tlsldm); + break; + case R_SW_64_GOTTPREL: + LDIH_GOT(Loc, Type, Val, sw64_tlsrelgot_gottprel); + break; + case R_SW_64_GPRELLOW: + case R_SW_64_GPREL16: + case R_SW_64_TPRELLO: + case R_SW_64_TPREL16: + case R_SW_64_DTPRELLO: + { + auto inst = Read32(Loc); + Val += inst & 0xffff; + Write32(Loc, bit_select32(inst, Val, 0xffff)); + }break; + default: + error(getErrorLocation(Loc) + "do not know how to relocate " + toString(Type)); + } +} + +static int32_t PltIndex; + +template +void Sw_64::writePltHeader(uint8_t *Buf) const { + const uint8_t PltData[] = { + 0x39, 0x01, 0x7c, 0x43, // subl $r27,$r28,$r25 + 0x00, 0x00, 0x9c, 0xff, // ldih $r28,0($r28) <--- needs relocation. + 0x79, 0x01, 0x39, 0x43, // s4subl $r25,$r25,$r25 + 0x00, 0x00, 0x9c, 0xfb, // ldi $r28,0($r28) <--- needs relocation. + 0x00, 0x00, 0x7c, 0x8f, // ldl $r27,0($r28) + 0x19, 0x01, 0x39, 0x43, // addl $r25,$r25,$r25 + 0x08, 0x00, 0x9c, 0x8f, // ldl $r28,8($r28) + 0x00, 0x00, 0xfb, 0x0f, // jmp $r31,($r27),1200020, 0x<_PROCEDURE_LINKAGE_TABLE_+0x20> + 0xf7, 0xff, 0x9f, 0x13, // br $r28,1200000, 0x<_PROCEDURE_LINKAGE_TABLE_> + }; + if(sizeof(PltData) != this->pltHeaderSize)error("Wrong PLT header data."); + memcpy(Buf, PltData, sizeof(PltData)); + constexpr int Addend = 8; + Relocation rel; + rel.type = (R_SW_64_GPDISP | (Addend << 8)); + // $28 point to PLT[0], need to be relocated to the beginning of .got.plt section. + auto Val = in.gotPlt->getVA() - in.plt->getVA() - sizeof(PltData) + Addend; + relocate(Buf + 4, rel, Val); + PltIndex = 0; +} + +template +void Sw_64::writePlt(uint8_t *buf, const Symbol &sym, + uint64_t pltEntryAddr) const { + // `Index` is useless when multiple entries for the same function. + Write32(buf, 0x13fffffe - PltIndex++); + +} + +template TargetInfo *elf::getSw_64TargetInfo() { + static Sw_64 target; + return ⌖ +} + +template TargetInfo *elf::getSw_64TargetInfo(); diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index 89955db67733..048c3e54ca44 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -33,6 +33,7 @@ add_lld_library(lldELF Arch/PPC64.cpp Arch/RISCV.cpp Arch/SPARCV9.cpp + Arch/Sw_64.cpp Arch/X86.cpp Arch/X86_64.cpp ARMErrataFix.cpp diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 94af8c34beb7..362536c61178 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -278,6 +278,10 @@ struct Config { bool isStatic = false; bool sysvHash = false; bool target1Rel; + bool sw64_tlsrelgot_tlsgd; + bool sw64_tlsrelgot_tlsldm; + bool sw64_tlsrelgot_gottprel; + bool sw64_tlsrelgot_gotdtprel; bool trace; bool thinLTOEmitImportsFiles; bool thinLTOEmitIndexFiles; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index e65dfa553de0..058985c9e569 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -193,6 +193,7 @@ static std::tuple parseEmulation(StringRef emul) { .Case("msp430elf", {ELF32LEKind, EM_MSP430}) .Case("elf64_amdgpu", {ELF64LEKind, EM_AMDGPU}) .Case("elf64loongarch", {ELF64LEKind, EM_LOONGARCH}) + .Cases("elf64-sw_64", "elf64sw_64", {ELF64LEKind, EM_SW64}) .Default({ELFNoneKind, EM_NONE}); if (ret.first == ELFNoneKind) @@ -1101,7 +1102,7 @@ static bool getIsRela(opt::InputArgList &args) { uint16_t m = config->emachine; return m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || m == EM_LOONGARCH || m == EM_PPC || m == EM_PPC64 || m == EM_RISCV || - m == EM_X86_64; + m == EM_SW64 || m == EM_X86_64; } static void parseClangOption(StringRef opt, const Twine &msg) { @@ -1355,6 +1356,16 @@ static void readConfigs(opt::InputArgList &args) { config->timeTraceEnabled = args.hasArg(OPT_time_trace_eq); config->timeTraceGranularity = args::getInteger(args, OPT_time_trace_granularity, 500); + + config->sw64_tlsrelgot_tlsgd = + args.hasFlag(OPT_sw64_tlsrelgot_tlsgd, OPT_no_sw64_tlsrelgot_tlsgd, false); + config->sw64_tlsrelgot_tlsldm = + args.hasFlag(OPT_sw64_tlsrelgot_tlsldm, OPT_no_sw64_tlsrelgot_tlsldm, false); + config->sw64_tlsrelgot_gottprel = + args.hasFlag(OPT_sw64_tlsrelgot_gottprel, OPT_no_sw64_tlsrelgot_gottprel, false); + config->sw64_tlsrelgot_gotdtprel = + args.hasFlag(OPT_sw64_tlsrelgot_gotdtprel, OPT_no_sw64_tlsrelgot_gotdtprel, false); + config->trace = args.hasArg(OPT_trace); config->undefined = args::getStrings(args, OPT_undefined); config->undefinedVersion = @@ -2632,7 +2643,7 @@ void LinkerDriver::link(opt::InputArgList &args) { // If a --hash-style option was not given, set to a default value, // which varies depending on the target. if (!args.hasArg(OPT_hash_style)) { - if (config->emachine == EM_MIPS) + if (config->emachine == EM_MIPS || config->emachine == EM_SW64) config->sysvHash = true; else config->sysvHash = config->gnuHash = true; diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index d96b47b3585b..8a3c6821bacc 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1594,6 +1594,8 @@ static uint16_t getBitcodeMachineKind(StringRef path, const Triple &t) { case Triple::riscv32: case Triple::riscv64: return EM_RISCV; + case Triple::sw_64: + return EM_SW64; case Triple::x86: return t.isOSIAMCU() ? EM_IAMCU : EM_386; case Triple::x86_64: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 44444b62251d..4b72595b0196 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -462,9 +462,12 @@ void InputSection::copyRelocations(uint8_t *buf, addend += sec->getFile()->mipsGp0; } - if (RelTy::IsRela) + if (RelTy::IsRela) { + if (config->emachine == EM_SW64 && + (R_SW_64_GPDISP == type || R_SW_64_LITUSE == type)) + continue; p->r_addend = sym.getVA(addend) - section->getOutputSection()->addr; - else if (config->relocatable && type != target.noneRel) + } else if (config->relocatable && type != target.noneRel) sec->addReloc({R_ABS, type, rel.offset, addend, &sym}); } else if (config->emachine == EM_PPC && type == R_PPC_PLTREL24 && p->r_addend >= 0x8000 && sec->file->ppc32Got2) { @@ -634,6 +637,7 @@ static int64_t getTlsTpOffset(const Symbol &s) { // Variant 1. case EM_ARM: case EM_AARCH64: + case EM_SW64: return s.getVA(0) + config->wordsize * 2 + ((tls->p_vaddr - config->wordsize * 2) & (tls->p_align - 1)); case EM_MIPS: @@ -867,6 +871,21 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, return in.got->getTlsIndexOff() + a; case R_TLSLD_PC: return in.got->getTlsIndexVA() + a - p; + case R_SW_HINT_PC: { + uint64_t symVA = sym.getVA(a); + return 0 == symVA ? 4 : symVA - p; + } + case R_SW_GOT_OFF: + case R_SW_PLT_GOT_OFF: + return in.sw64Got->getSymEntryOffset(file, sym, a, expr) - + in.sw64Got->getGpOffset(file); + case R_SW_GOTREL: + return sym.getVA(a) - in.sw64Got->getVA() - in.sw64Got->getGpOffset(file); + case R_SW_GOT_GP_PC: + return in.sw64Got->getVA() + in.sw64Got->getGpOffset(file) + a - p; + case R_SW_TLSGD_GOT: + return in.sw64Got->getDynOffset(file, sym) - + in.sw64Got->getGpOffset(file); default: llvm_unreachable("invalid expression"); } diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index bb06d303d598..4f8ea4fd4d2b 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -278,6 +278,10 @@ def library: JoinedOrSeparate<["-"], "l">, MetaVarName<"">, def library_path: JoinedOrSeparate<["-"], "L">, MetaVarName<"">, HelpText<"Add to the library search path">; +defm literalgot: B<"literalgot", + "Support LITERAL_GOT relocation", + "Do not support LITERAL_GOT relocation (default)">; + def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; defm Map: Eq<"Map", "Print a link map to the specified file">; @@ -448,6 +452,19 @@ def : FF<"time-trace">, Alias, defm time_trace_granularity: EEq<"time-trace-granularity", "Minimum time granularity (in microseconds) traced by time profiler">; +defm sw64_tlsrelgot_tlsgd: B<"sw64_tlsrelgot_tlsgd", + "Support TLSREL_GOT relocation on TLSGD", + "Do not support TLSREL_GOT relocation on TLSGD (default)">; +defm sw64_tlsrelgot_tlsldm: B<"sw64_tlsrelgot_tlsldm", + "Support TLSREL_GOT relocation on TLSLDM", + "Do not support TLSREL_GOT relocation on TLSLDM (default)">; +defm sw64_tlsrelgot_gottprel: B<"sw64_tlsrelgot_gottprel", + "Support TLSREL_GOT relocation on GOTTPREL", + "Do not support TLSREL_GOT relocation on GOTTPREL (default)">; +defm sw64_tlsrelgot_gotdtprel: B<"sw64_tlsrelgot_gotdtprel", + "Support TLSREL_GOT relocation on GOTDTPREL", + "Do not support TLSREL_GOT relocation on GOTDTPREL (default)">; + defm toc_optimize : BB<"toc-optimize", "(PowerPC64) Enable TOC related optimizations (default)", "(PowerPC64) Disable TOC related optimizations">; @@ -731,12 +748,14 @@ def plugin_opt_eq : J<"plugin-opt=">; // Options listed below are silently ignored for now for compatibility. def: Flag<["-"], "d">; def: Flag<["-"], "g">; +def: J<"hash-size=">; def: F<"long-plt">; def: FF<"no-add-needed">; def: F<"no-copy-dt-needed-entries">; def: F<"no-ctors-in-init-array">; def: F<"no-keep-memory">; def: F<"no-warn-mismatch">; +def: F<"reduce-memory-overheads">; def: Separate<["--", "-"], "rpath-link">; def: J<"rpath-link=">; def: F<"secure-plt">; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index af15f5a92546..60263a586843 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -205,8 +205,8 @@ static bool needsPlt(RelExpr expr) { static bool needsGot(RelExpr expr) { return oneof( - expr); + R_AARCH64_GOT_PAGE, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC, + R_SW_GOT_OFF, R_SW_PLT_GOT_OFF>(expr); } // True if this expression is of the form Sym - X, where X is a position in the @@ -214,8 +214,8 @@ static bool needsGot(RelExpr expr) { static bool isRelExpr(RelExpr expr) { return oneof( - expr); + R_RISCV_PC_INDIRECT, R_PPC64_RELAX_GOT_PC, R_LOONGARCH_PAGE_PC, + R_SW_PLT_GOT_OFF>(expr); } static RelExpr toPlt(RelExpr expr) { @@ -228,6 +228,8 @@ static RelExpr toPlt(RelExpr expr) { return R_PLT_PC; case R_ABS: return R_PLT; + case R_SW_GOT_OFF: + return R_SW_PLT_GOT_OFF; default: return expr; } @@ -246,6 +248,8 @@ static RelExpr fromPlt(RelExpr expr) { return R_PPC64_CALL; case R_PLT: return R_ABS; + case R_SW_PLT_GOT_OFF: + return R_SW_GOT_OFF; case R_PLT_GOTPLT: return R_GOTPLTREL; default: @@ -853,6 +857,64 @@ RelType RelocationScanner::getMipsN32RelType(RelTy *&rel) const { return type; } +template +static RelType getSw64RelType(RelTy *&I, RelTy *const E) { + static __thread RelTy *last_rel = nullptr; + static __thread RelTy *last_tls_rel = nullptr; + RelType Type = R_SW_64_NONE; + auto prev = I++; + Type = prev->getType(false); + switch (0xff & Type) { + case R_SW_64_GPDISP: + // TODO: Check addend overflow for huge function? + Type |= (getAddend(*prev) << 8); + break; + case R_SW_64_LITERAL: { + if (nullptr != last_rel && + R_SW_64_LITERAL_GOT == last_rel->getType(false)) { + auto addend = last_rel->r_offset - prev->r_offset; + // TODO: Check addend overflow. + Type |= (addend << 16); + } + if (E != I && R_SW_64_LITUSE == I->getType(false)) { + auto addend = getAddend(*I); + // TODO: Check addend overflow. + Type |= addend << 8; + } + } break; + case R_SW_64_TLSGD: + case R_SW_64_TLSLDM: + case R_SW_64_GOTTPREL: + case R_SW_64_GOTDTPREL: + if (nullptr != last_tls_rel && + R_SW_64_TLSREL_GOT == last_tls_rel->getType(false)) { + auto addend = last_tls_rel->r_offset - prev->r_offset; + // TODO: Check addend overflow. + Type |= (addend << 16); + } + break; + case R_SW_64_LITUSE: + Type = R_SW_64_NONE; + break; + case R_SW_64_TLSREL_GOT: + if (E != I) { + last_tls_rel = prev; + return R_SW_64_NONE; + } + break; + case R_SW_64_LITERAL_GOT: + if (E != I) { + last_rel = prev; + return R_SW_64_NONE; + } + // fallthrough + default: + break; + } + last_rel = nullptr; + return Type; +} + template static void addRelativeReloc(InputSectionBase &isec, uint64_t offsetInSec, Symbol &sym, int64_t addend, RelExpr expr, @@ -957,8 +1019,8 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTPLT, R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE, - R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>( - e)) + R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC, + R_SW_GOT_OFF, R_SW_PLT_GOT_OFF, R_SW_GOTREL, R_SW_GOT_GP_PC>(e)) return true; // These never do, except if the entire file is position dependent or if @@ -1062,6 +1124,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset, // for detailed description: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf in.mipsGot->addEntry(*sec->file, sym, addend, expr); + } else if (config->emachine == EM_SW64) { + in.sw64Got->addEntry(*sec->file, sym, addend, expr); } else if (!sym.isTls() || config->emachine != EM_LOONGARCH) { // Many LoongArch TLS relocs reuse the R_LOONGARCH_GOT type, in which // case the NEEDS_GOT flag shouldn't get set. @@ -1145,6 +1209,16 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset, return; } + if (config->emachine == EM_SW64) { + error("can't create dynamic relocation " + toString(type) + " against " + + (sym.getName().empty() ? "local symbol" + : "symbol: " + toString(sym)) + + " in readonly segment; " + "pass '-Wl,-z,notext' to allow text relocations in the output" + + getLocation(*sec, sym, offset)); + return; + } + if (sym.isObject()) { // Produce a copy relocation. if (auto *ss = dyn_cast(&sym)) { @@ -1225,6 +1299,39 @@ static unsigned handleMipsTlsRelocation(RelType type, Symbol &sym, return 0; } +static unsigned handleSw64TlsRelocation(RelType Type, Symbol &Sym, + InputSectionBase &C, uint64_t Offset, + int64_t Addend, RelExpr Expr) { + // Local dynamic. + if (oneof(Expr) && R_SW_64_TLSLDM == Type) { + // TODO: relax + in.sw64Got->addTlsIndex(*C.file); + C.relocations.push_back({Expr, Type, Offset, Addend, nullptr}); + return target->getTlsGdRelaxSkip(Type); + } + + // Global dynamic. + if (oneof(Expr)) { + // TODO: relax + in.sw64Got->addDynTlsEntry(*C.file, Sym); + C.relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return target->getTlsGdRelaxSkip(Type); + } + + if (R_TPREL == Expr) { + assert(nullptr == dyn_cast(&Sym)); + C.relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return 1; + } + + if (R_DTPREL == Expr) { + C.addReloc({Expr, Type, Offset, Addend, &Sym}); + return 1; + } + + return 0; +} + // Notes about General Dynamic and Local Dynamic TLS models below. They may // require the generation of a pair of GOT entries that have associated dynamic // relocations. The pair of GOT entries created are of the form GOT[e0] Module @@ -1247,6 +1354,9 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym, if (config->emachine == EM_MIPS) return handleMipsTlsRelocation(type, sym, c, offset, addend, expr); + if (config->emachine == EM_SW64) + return handleSw64TlsRelocation(type, sym, c, offset, addend, expr); + if (oneof(expr) && config->shared) { @@ -1360,6 +1470,8 @@ template void RelocationScanner::scanOne(RelTy *&i) { RelType type; if (config->mipsN32Abi) { type = getMipsN32RelType(i); + } else if (config->emachine == EM_SW64) { + type = getSw64RelType(i, static_cast(end)); } else { type = rel.getType(config->isMips64EL); ++i; @@ -1389,6 +1501,11 @@ template void RelocationScanner::scanOne(RelTy *&i) { maybeReportUndefined(cast(sym), *sec, offset)) return; + if (R_SW_HINT_PC == expr) { + sec->relocations.push_back({expr, type, offset, addend, &sym}); + return; + } + if (config->emachine == EM_PPC64) { // We can separate the small code model relocations into 2 categories: // 1) Those that access the compiler generated .toc sections. @@ -1534,7 +1651,7 @@ template void elf::scanRelocations() { // for -z nocombreloc. MIPS and PPC64 use global states which are not suitable // for parallelism. bool serial = !config->zCombreloc || config->emachine == EM_MIPS || - config->emachine == EM_PPC64; + config->emachine == EM_PPC64 || config->emachine == EM_SW64; parallel::TaskGroup tg; for (ELFFileBase *f : ctx.objectFiles) { auto fn = [f]() { diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index e36215bd0d93..250b290a44b2 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -111,6 +111,12 @@ enum RelExpr { R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC, R_LOONGARCH_TLSGD_PAGE_PC, + R_SW_HINT_PC, + R_SW_GOT_OFF, + R_SW_PLT_GOT_OFF, + R_SW_GOTREL, + R_SW_GOT_GP_PC, + R_SW_TLSGD_GOT, }; // Architecture-neutral representation of relocation. diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index 3577e78c0d98..46f92e1ef042 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -447,6 +447,7 @@ static std::pair parseBfdName(StringRef s) { .Case("elf32-msp430", {ELF32LEKind, EM_MSP430}) .Case("elf32-loongarch", {ELF32LEKind, EM_LOONGARCH}) .Case("elf64-loongarch", {ELF64LEKind, EM_LOONGARCH}) + .Cases("elf64-sw_64", "elf64sw_64", {ELF64LEKind, EM_SW64}) .Default({ELFNoneKind, EM_NONE}); } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index de25750bf9eb..35571235fb81 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1129,6 +1129,230 @@ void MipsGotSection::writeTo(uint8_t *buf) { } } +Sw64GotSection::Sw64GotSection() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, + ".got") {} + +// True if non-preemptable symbol always has the same value regardless of where +// the DSO is loaded. +static bool isAbsolute(const Symbol &Sym) { + if (Sym.isUndefWeak()) + return true; + if (const auto *DR = dyn_cast(&Sym)) + return DR->section == nullptr; // Absolute symbol. + return false; +} + +void Sw64GotSection::build() { + for (auto i = std::begin(Gots); i < std::end(Gots); ++i) { + if (nullptr == i->File) + continue; + for (auto j = std::next(i); j < std::end(Gots); ++j) { + if (nullptr == j->File) + continue; + mergeGots(*i, *j); + if (MAX_GOTS <= i->getEntriesNum()) + break; + } + } + + // Calculate indexes for each GOT entry. + size_t Index = 0; + uint32_t PltIndex = 0; + for (auto &Got : Gots) { + if (nullptr == Got.File) + continue; + Got.StartIndex = Index; + for (auto &P : Got.Global) { + P.second = Index++; + + auto Sym = P.first.first; + auto Addend = P.first.second; + uint64_t Offset = P.second * config->wordsize; + mainPart->relaDyn->addReloc( + {Sym->isTls() ? target->tlsGotRel : target->gotRel, this, Offset, + DynamicReloc::AgainstSymbolWithTargetVA, *Sym, Addend, R_ADDEND}); + if (0 != Addend || (Sym->isDefined() && Sym->isWeak())) { + relocations.push_back({R_ABS, R_SW_64_REFQUAD, Offset, Addend, Sym}); + } + } + + for (auto &P : Got.Jump) { + P.second = Index++; + + auto Sym = P.first.first; + + auto Addend = P.first.second; + uint64_t Offset = P.second * config->wordsize; + assert(0 == Addend); + in.plt->addEntry(*Sym); + Addend += target->pltEntrySize * (PltIndex - Sym->getPltIdx()); + relocations.push_back({R_PLT, target->gotRel, Offset, Addend, Sym}); + in.relaPlt->addReloc({target->pltRel, this, Offset, + DynamicReloc::AgainstSymbolWithTargetVA, *Sym, 0, + R_ADDEND}); + + ++PltIndex; + } + // Add the only one entry to make it not empty and to compensate + // the size when necessary. + if (!Got.Jump.empty() && !in.gotPlt->isNeeded()) { + in.gotPlt->addEntry(*Got.Jump.front().first.first); + } + + for (auto &P : Got.Local) { + P.second = Index++; + + auto Sym = P.first.first; + auto Addend = P.first.second; + uint64_t Offset = P.second * config->wordsize; + if (!config->isPic || isAbsolute(*Sym)) { + relocations.push_back({Sym->isTls() ? R_TPREL : R_ABS, target->gotRel, + Offset, Addend, Sym}); + } else { + mainPart->relaDyn->addReloc( + DynamicReloc::AgainstSymbolWithTargetVA, + Sym->isTls() ? target->tlsGotRel : target->relativeRel, *this, + Offset, *Sym, Addend, R_ABS, target->gotRel); + } + } + + for (auto &P : Got.DynTls) { + P.second = Index; + Index += DYNAMIC_GOT_COUNT; + + auto Sym = P.first; + uint64_t Offset = P.second * config->wordsize; + uint64_t Offset2 = Offset + config->wordsize; + if (config->shared || nullptr == Sym || Sym->isPreemptible) { + if (nullptr == Sym) { + mainPart->relaDyn->addReloc({R_SW_64_DTPMOD64, this, Offset, + DynamicReloc::AddendOnly, *Sym, 0, + R_ADDEND}); + continue; + } + mainPart->relaDyn->addReloc({R_SW_64_DTPMOD64, this, Offset, + DynamicReloc::AgainstSymbol, *Sym, 0, + R_ADDEND}); + } + if (Sym->isPreemptible) { + mainPart->relaDyn->addReloc({R_SW_64_DTPREL64, this, Offset2, + DynamicReloc::AgainstSymbol, *Sym, 0, + R_ADDEND}); + } else { + if (!config->shared) { + relocations.push_back({ + R_ABS, + R_SW_64_DTPMOD64, + Offset, + 1, + Sym, + }); + } + relocations.push_back({ + R_ABS, + R_SW_64_TPREL64, + Offset2, + 0, + Sym, + }); + } + } + } +} + +bool Sw64GotSection::updateAllocSize() { + Size = 0; + for (const FileGot &G : Gots) { + if (nullptr == G.File) + continue; + Size += G.getEntriesNum() * config->wordsize; + } + return false; +} + +size_t Sw64GotSection::FileGot::getEntriesNum() const { + return Local.size() + Global.size() + Jump.size() + + DynTls.size() * DYNAMIC_GOT_COUNT; +} + +void Sw64GotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend, + RelExpr Expr) { + FileGot &G = getGot(File); + if (Sym.isPreemptible) { + auto &Entries = R_SW_PLT_GOT_OFF == Expr ? G.Jump : G.Global; + Entries.insert({{&Sym, Addend}, 0}); + } else { + G.Local.insert({{&Sym, Addend}, 0}); + } +} + +uint64_t Sw64GotSection::getSymEntryOffset(const InputFile *F, const Symbol &S, + int64_t Addend, + RelExpr Expr) const { + const FileGot &G = Gots[F->mipsGotIndex]; + Symbol *Sym = const_cast(&S); + if (Sym->isPreemptible) { + auto &Entries = R_SW_PLT_GOT_OFF == Expr ? G.Jump : G.Global; + return Entries.lookup({Sym, Addend}) * config->wordsize; + } + return G.Local.lookup({Sym, Addend}) * config->wordsize; +} + +void Sw64GotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) { + getGot(File).DynTls.insert({&Sym, 0}); +} + +void Sw64GotSection::addTlsIndex(InputFile &File) { + getGot(File).DynTls.insert({nullptr, 0}); +} + +uint64_t Sw64GotSection::getDynOffset(const InputFile *F, + const Symbol &S) const { + const FileGot &G = Gots[F->mipsGotIndex]; + Symbol *Sym = const_cast(&S); + return G.DynTls.lookup(Sym) * config->wordsize; +} + +uint64_t Sw64GotSection::getGpOffset(const InputFile *F) const { + uint64_t offset = GP_OFFSET; + if (F && uint32_t(-1) != F->mipsGotIndex) { + offset += Gots[F->mipsGotIndex].StartIndex * config->wordsize; + } + return offset; +} + +Sw64GotSection::FileGot &Sw64GotSection::getGot(InputFile &F) { + if (uint32_t(-1) == F.mipsGotIndex) { + Gots.emplace_back(); + Gots.back().File = &F; + F.mipsGotIndex = Gots.size() - 1; + } + return Gots[F.mipsGotIndex]; +} + +void Sw64GotSection::writeTo(uint8_t *buf) { + target->relocateAlloc(*this, buf); +} + +bool Sw64GotSection::mergeGots(FileGot &Dst, FileGot &Src) { + assert(nullptr != Dst.File); + + // TODO: Do an optimistic merge. + if (MAX_GOTS < Dst.getEntriesNum() + Src.getEntriesNum()) + return false; + + set_union(Dst.Local, Src.Local); + set_union(Dst.Global, Src.Global); + set_union(Dst.Jump, Src.Jump); + set_union(Dst.DynTls, Src.DynTls); + Src.File->mipsGotIndex = Dst.File->mipsGotIndex; + Src.File = nullptr; + + assert(Dst.getEntriesNum() <= MAX_GOTS); + return true; +} + // On PowerPC the .plt section is used to hold the table of function addresses // instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss // section. I don't know why we have a BSS style type for the section but it is @@ -1441,6 +1665,9 @@ DynamicSection::computeContents() { break; } addInt(DT_PLTREL, config->isRela ? DT_RELA : DT_REL); + if (config->emachine == EM_SW64) { + addInt(/* SW_64_PLTRO */ DT_LOPROC, 1); + } } if (config->emachine == EM_AARCH64) { @@ -2224,6 +2451,11 @@ template void SymbolTableSection::writeTo(uint8_t *buf) { eSym->st_name = ent.strTabOffset; eSym->setBindingAndType(sym->binding, sym->type); eSym->st_other = sym->stOther; + if (config->emachine == EM_SW64) { + // It's not clear what the flags `0x88` mean, but `bfd` doesn't copy it. + // So we mimic the behaviour of `bfd`. + eSym->st_other &= ~0x88; + } if (BssSection *commonSec = getCommonSec(sym)) { // When -r is specified, a COMMON symbol is not allocated. Its st_shndx diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 38d0c80a073d..29f932ccc87c 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -347,7 +347,59 @@ private: // Try to merge two GOTs. In case of success the `Dst` contains // result of merging and the function returns true. In case of // overflow the `Dst` is unchanged and the function returns false. - bool tryMergeGots(FileGot & dst, FileGot & src, bool isPrimary); + bool tryMergeGots(FileGot &dst, FileGot &src, bool isPrimary); +}; + +class Sw64GotSection final : public SyntheticSection { +public: + static constexpr int64_t GP_OFFSET = 0x8000; + static constexpr size_t DYNAMIC_GOT_COUNT = 2; + Sw64GotSection(); + + void writeTo(uint8_t *Buf) override; + size_t getSize() const override { return Size; } + bool updateAllocSize() override; + void finalizeContents() override { updateAllocSize(); } + + // Join separate GOTs built for each input file. + void build(); + + void addEntry(InputFile &File, Symbol &Sym, int64_t Addend, RelExpr Expr); + uint64_t getSymEntryOffset(const InputFile *F, const Symbol &S, + int64_t Addend, RelExpr Expr) const; + void addDynTlsEntry(InputFile &File, Symbol &Sym); + uint64_t getDynOffset(const InputFile *F, const Symbol &S) const; + void addTlsIndex(InputFile &File); + // Return gp value for particular input file. + uint64_t getGpOffset(const InputFile *F = nullptr) const; + +private: + uint64_t Size; + + // Symbol and addend. + typedef std::pair GotEntry; + + struct FileGot { + InputFile *File = nullptr; + size_t StartIndex = 0; + + llvm::MapVector Local; + llvm::MapVector Global; + llvm::MapVector Jump; + llvm::MapVector DynTls; + + // Total number of all entries. + size_t getEntriesNum() const; + }; + + // Container of GOT created for each input file. + std::vector Gots; + + // Return (and create if necessary) `FileGot`. + FileGot &getGot(InputFile &F); + + static constexpr size_t MAX_GOTS = 1 << 13; + static bool mergeGots(FileGot &Dst, FileGot &Src); }; class GotPltSection final : public SyntheticSection { @@ -709,6 +761,7 @@ public: HashTableSection(); void finalizeContents() override; void writeTo(uint8_t *buf) override; + template void writeTo(uint8_t *Buf); size_t getSize() const override { return size; } private: @@ -1321,6 +1374,7 @@ struct InStruct { std::unique_ptr relaIplt; std::unique_ptr shStrTab; std::unique_ptr strTab; + std::unique_ptr sw64Got; std::unique_ptr symTab; std::unique_ptr symTabShndx; diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 32bb2164a208..78f73c432112 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -89,6 +89,8 @@ TargetInfo *elf::getTarget() { return getSPARCV9TargetInfo(); case EM_X86_64: return getX86_64TargetInfo(); + case EM_SW64: + return getSw_64TargetInfo(); } llvm_unreachable("unknown target machine"); } diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index aeabe47f92a1..ee3c3994b498 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -190,6 +190,7 @@ TargetInfo *getSPARCV9TargetInfo(); TargetInfo *getX86TargetInfo(); TargetInfo *getX86_64TargetInfo(); template TargetInfo *getMipsTargetInfo(); +template TargetInfo *getSw_64TargetInfo(); struct ErrorPlace { InputSectionBase *isec; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index dd37bbbf76c1..2513bc9ab7be 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -434,6 +434,9 @@ template void elf::createSyntheticSections() { if (config->emachine == EM_MIPS) { in.mipsGot = std::make_unique(); add(*in.mipsGot); + } else if (config->emachine == EM_SW64) { + in.sw64Got = std::make_unique(); + add(*in.sw64Got); } else { in.got = std::make_unique(); add(*in.got); @@ -850,6 +853,9 @@ enum RankFlags { RF_NOT_RELRO = 1 << 9, RF_NOT_TLS = 1 << 8, RF_BSS = 1 << 7, + + RF_SW_64_GPREL = 1 << 2, + RF_SW_64_GOT = 1 << 1, }; static unsigned getSectionRank(const OutputSection &osec) { @@ -928,6 +934,16 @@ static unsigned getSectionRank(const OutputSection &osec) { if (osec.type == SHT_NOBITS) rank |= RF_BSS; + if (config->emachine == EM_SW64) { + StringRef name = osec.name; + // Matching bfd section layout to make `gprel16` works as bfd. + if (".got" == name) { + rank |= RF_SW_64_GOT; + } else if (".sdata" == name || ".sbss" == name) { + rank |= RF_SW_64_GPREL; + } + } + // Some architectures have additional ordering restrictions for sections // within the same PT_LOAD. if (config->emachine == EM_PPC64) { @@ -1955,6 +1971,18 @@ template void Writer::finalizeSections() { { llvm::TimeTraceScope timeScope("Add symbols to symtabs"); + + if (nullptr != in.sw64Got) { + in.sw64Got->build(); + if (in.plt->isNeeded()) { + // Make it compatible with bfd. + Symbol *s = symtab.addSymbol(Defined{ + /*file*/ nullptr, "_PROCEDURE_LINKAGE_TABLE_", STB_LOCAL, + STV_DEFAULT, STT_OBJECT, /*value*/ 0, /*size*/ 0, in.plt.get()}); + s->isUsedInRegularObj = true; + } + } + // Now that we have defined all possible global symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. for (Symbol *sym : symtab.getSymbols()) { @@ -2073,6 +2101,7 @@ template void Writer::finalizeSections() { finalizeSynthetic(in.strTab.get()); finalizeSynthetic(in.got.get()); finalizeSynthetic(in.mipsGot.get()); + finalizeSynthetic(in.sw64Got.get()); finalizeSynthetic(in.igotPlt.get()); finalizeSynthetic(in.gotPlt.get()); finalizeSynthetic(in.relaIplt.get()); @@ -2678,9 +2707,11 @@ template void Writer::setPhdrs(Partition &part) { // musl/glibc ld.so rounds the size down, so we need to round up // to protect the last page. This is a no-op on FreeBSD which always // rounds up. - p->p_memsz = - alignToPowerOf2(p->p_offset + p->p_memsz, config->commonPageSize) - - p->p_offset; + if (config->emachine != EM_SW64) { + p->p_memsz = + alignToPowerOf2(p->p_offset + p->p_memsz, config->commonPageSize) - + p->p_offset; + } } } } -- Gitee From fdfc3943b5fd6338b2b61861ffc7a5fed5ba29b0 Mon Sep 17 00:00:00 2001 From: swcompiler Date: Fri, 30 May 2025 16:50:00 +0800 Subject: [PATCH 2/2] [Sw64] Add Sw64 target support for compiler-rt --- clang/lib/Driver/ToolChains/Linux.cpp | 7 +- .../cmake/Modules/AllSupportedArchDefs.cmake | 27 +- compiler-rt/lib/asan/asan_allocator.h | 4 + compiler-rt/lib/asan/asan_interceptors.cpp | 2 + compiler-rt/lib/asan/asan_mapping.h | 9 + compiler-rt/lib/asan/tests/asan_test.cpp | 5 +- compiler-rt/lib/fuzzer/FuzzerPlatform.h | 4 + compiler-rt/lib/fuzzer/FuzzerTracePC.cpp | 2 +- compiler-rt/lib/lsan/lsan_allocator.cpp | 2 +- compiler-rt/lib/lsan/lsan_common.cpp | 2 + compiler-rt/lib/lsan/lsan_common.h | 2 + compiler-rt/lib/msan/msan.h | 12 + compiler-rt/lib/msan/msan_allocator.cpp | 14 ++ .../lib/sanitizer_common/sanitizer_asm.h | 2 +- .../sanitizer_common_interceptors.inc | 5 + .../sanitizer_common_syscalls.inc | 4 +- .../lib/sanitizer_common/sanitizer_linux.cpp | 176 ++++++++++++- .../lib/sanitizer_common/sanitizer_linux.h | 3 +- .../sanitizer_linux_libcdep.cpp | 8 +- .../lib/sanitizer_common/sanitizer_platform.h | 8 + .../sanitizer_platform_interceptors.h | 10 +- .../sanitizer_platform_limits_linux.cpp | 2 +- .../sanitizer_platform_limits_posix.cpp | 18 +- .../sanitizer_platform_limits_posix.h | 20 +- .../sanitizer_common/sanitizer_stacktrace.h | 2 + .../sanitizer_stoptheworld_linux_libcdep.cpp | 9 +- .../sanitizer_symbolizer_libcdep.cpp | 2 + .../lib/sanitizer_common/tests/CMakeLists.txt | 2 +- .../tests/sanitizer_allocator_test.cpp | 2 + .../tests/sanitizer_ioctl_test.cpp | 8 + compiler-rt/lib/tsan/rtl/CMakeLists.txt | 4 + .../lib/tsan/rtl/tsan_interceptors_posix.cpp | 19 +- compiler-rt/lib/tsan/rtl/tsan_interface.h | 2 +- compiler-rt/lib/tsan/rtl/tsan_platform.h | 42 ++++ .../lib/tsan/rtl/tsan_platform_linux.cpp | 6 + compiler-rt/lib/tsan/rtl/tsan_rtl.h | 2 +- compiler-rt/lib/tsan/rtl/tsan_rtl_sw64.S | 233 ++++++++++++++++++ compiler-rt/lib/xray/CMakeLists.txt | 6 + compiler-rt/lib/xray/xray_interface.cpp | 2 + compiler-rt/lib/xray/xray_sw64.cpp | 152 ++++++++++++ compiler-rt/lib/xray/xray_trampoline_sw64.S | 99 ++++++++ compiler-rt/lib/xray/xray_tsc.h | 2 +- compiler-rt/test/asan/CMakeLists.txt | 2 +- .../test/asan/TestCases/Linux/ptrace.cpp | 10 + compiler-rt/test/fuzzer/fork-ubsan.test | 2 +- compiler-rt/test/lit.common.cfg.py | 6 +- .../test/lsan/TestCases/use_registers.cpp | 2 + compiler-rt/test/lsan/lit.common.cfg.py | 1 + .../test/sanitizer_common/print_address.h | 4 +- compiler-rt/test/tsan/map32bit.cpp | 1 + compiler-rt/test/tsan/mmap_large.cpp | 2 +- llvm/lib/Target/Sw64/Sw64AsmPrinter.cpp | 13 + .../Instrumentation/AddressSanitizer.cpp | 4 + .../Instrumentation/MemorySanitizer.cpp | 181 ++++++++++++++ 54 files changed, 1111 insertions(+), 59 deletions(-) create mode 100644 compiler-rt/lib/tsan/rtl/tsan_rtl_sw64.S create mode 100644 compiler-rt/lib/xray/xray_sw64.cpp create mode 100644 compiler-rt/lib/xray/xray_trampoline_sw64.S diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 9557e5f1e348..235b6849b169 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -1061,6 +1061,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; const bool IsMIPS = getTriple().isMIPS32(); const bool IsMIPS64 = getTriple().isMIPS64(); + const bool IsSw64 = getTriple().isSw64(); const bool IsPowerPC64 = getTriple().getArch() == llvm::Triple::ppc64 || getTriple().getArch() == llvm::Triple::ppc64le; const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 || @@ -1086,15 +1087,15 @@ SanitizerMask Linux::getSupportedSanitizers() const { if (IsX86_64 || IsMIPS64 || IsAArch64 || IsLoongArch64) Res |= SanitizerKind::DataFlow; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 || - IsRISCV64 || IsSystemZ || IsHexagon || IsLoongArch64) + IsRISCV64 || IsSystemZ || IsHexagon || IsLoongArch64 || IsSw64) Res |= SanitizerKind::Leak; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ || - IsLoongArch64) + IsLoongArch64 || IsSw64) Res |= SanitizerKind::Thread; if (IsX86_64 || IsSystemZ) Res |= SanitizerKind::KernelMemory; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch || - IsPowerPC64 || IsHexagon || IsLoongArch64 || IsRISCV64) + IsPowerPC64 || IsHexagon || IsLoongArch64 || IsRISCV64 || IsSw64) Res |= SanitizerKind::Scudo; if (IsX86_64 || IsAArch64 || IsRISCV64) { Res |= SanitizerKind::HWAddress; diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake index 9b0a4655cd65..cdc72b6cd133 100644 --- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake +++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake @@ -13,6 +13,7 @@ set(RISCV64 riscv64) set(S390X s390x) set(SPARC sparc) set(SPARCV9 sparcv9) +set(SW64 sw_64) set(WASM32 wasm32) set(WASM64 wasm64) set(VE ve) @@ -25,12 +26,12 @@ endif() set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64} ${RISCV64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9} - ${HEXAGON} ${LOONGARCH64}) + ${HEXAGON} ${LOONGARCH64} ${SW64}) set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON} - ${LOONGARCH64}) + ${LOONGARCH64} ${SW64}) set(ALL_ASAN_ABI_SUPPORTED_ARCH ${X86_64} ${ARM64}) -set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${LOONGARCH64}) +set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${LOONGARCH64} ${SW64}) if(ANDROID) set(OS_NAME "Android") @@ -40,7 +41,7 @@ endif() if(OS_NAME MATCHES "Linux") set(ALL_FUZZER_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${S390X} - ${RISCV64} ${LOONGARCH64}) + ${RISCV64} ${LOONGARCH64} ${SW64}) elseif (OS_NAME MATCHES "Windows") set(ALL_FUZZER_SUPPORTED_ARCH ${X86} ${X86_64}) elseif(OS_NAME MATCHES "Android") @@ -51,12 +52,12 @@ else() set(ALL_FUZZER_SUPPORTED_ARCH ${X86_64} ${ARM64}) endif() -set(ALL_GWP_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}) +set(ALL_GWP_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${SW64}) if(APPLE) set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) else() set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32} - ${PPC64} ${S390X} ${RISCV64} ${HEXAGON} ${LOONGARCH64}) + ${PPC64} ${S390X} ${RISCV64} ${HEXAGON} ${LOONGARCH64} ${SW64}) endif() set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X} ${LOONGARCH64}) @@ -64,23 +65,23 @@ set(ALL_HWASAN_SUPPORTED_ARCH ${X86_64} ${ARM64} ${RISCV64}) set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64}) set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} ${PPC64} ${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON} - ${RISCV32} ${RISCV64} ${LOONGARCH64}) + ${RISCV32} ${RISCV64} ${LOONGARCH64} ${SW64}) set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X} - ${LOONGARCH64}) + ${LOONGARCH64} ${SW64}) set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON} - ${LOONGARCH64}) + ${LOONGARCH64} ${SW64}) set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64} - ${HEXAGON} ${LOONGARCH64}) + ${HEXAGON} ${LOONGARCH64} ${SW64}) set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS64} - ${HEXAGON} ${LOONGARCH64}) + ${HEXAGON} ${LOONGARCH64} ${SW64}) set(ALL_SCUDO_STANDALONE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} - ${MIPS32} ${MIPS64} ${PPC64} ${HEXAGON} ${LOONGARCH64} ${RISCV64}) + ${MIPS32} ${MIPS64} ${PPC64} ${HEXAGON} ${LOONGARCH64} ${RISCV64} ${SW64}) if(APPLE) set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM64}) else() set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} - powerpc64le ${HEXAGON} ${LOONGARCH64}) + powerpc64le ${HEXAGON} ${LOONGARCH64} ${SW64}) endif() set(ALL_SHADOWCALLSTACK_SUPPORTED_ARCH ${ARM64}) diff --git a/compiler-rt/lib/asan/asan_allocator.h b/compiler-rt/lib/asan/asan_allocator.h index ffeedadf0772..672084048c1b 100644 --- a/compiler-rt/lib/asan/asan_allocator.h +++ b/compiler-rt/lib/asan/asan_allocator.h @@ -140,6 +140,10 @@ typedef VeryDenseSizeClassMap SizeClassMap; const uptr kAllocatorSpace = ~(uptr)0; const uptr kAllocatorSize = 0x20000000000ULL; // 2T. typedef DefaultSizeClassMap SizeClassMap; +# elif SANITIZER_SW64 +const uptr kAllocatorSpace = ~(uptr)0; +const uptr kAllocatorSize = 0x40000000000ULL; // 4T. +typedef DefaultSizeClassMap SizeClassMap; # elif SANITIZER_WINDOWS const uptr kAllocatorSpace = ~(uptr)0; const uptr kAllocatorSize = 0x8000000000ULL; // 500G diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index 5158e99b75e5..f517e427099c 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -45,6 +45,8 @@ # define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1" # elif defined(__mips__) && SANITIZER_LINUX # define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2" +# elif defined(__sw_64__) +# define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1" # endif namespace __asan { diff --git a/compiler-rt/lib/asan/asan_mapping.h b/compiler-rt/lib/asan/asan_mapping.h index c5f95c07a210..d2ee11ab0702 100644 --- a/compiler-rt/lib/asan/asan_mapping.h +++ b/compiler-rt/lib/asan/asan_mapping.h @@ -79,6 +79,13 @@ // || `[0x0d55550000, 0x0effff9fff]` || LowShadow || // || `[0x0000000000, 0x0d5554ffff]` || LowMem || // +// Default Linux/SW64 mapping: +// || `[0x4000000000000, 0xfffffffffffff]` || HighMem || +// || `[0x2800000000000, 0x3ffffffffffff]` || HighShadow || +// || `[0x2400000000000, 0x27fffffffffff]` || ShadowGap || +// || `[0x2000000000000, 0x23fffffffffff]` || LowShadow || +// || `[0x0000000000000, 0x1ffffffffffff]` || LowMem || +// // Default Linux/AArch64 (39-bit VMA) mapping: // || `[0x2000000000, 0x7fffffffff]` || highmem || // || `[0x1400000000, 0x1fffffffff]` || highshadow || @@ -205,6 +212,8 @@ # define ASAN_SHADOW_OFFSET_CONST 0x0000080000000000 # elif SANITIZER_LOONGARCH64 # define ASAN_SHADOW_OFFSET_CONST 0x0000400000000000 +# elif SANITIZER_SW64 +# define ASAN_SHADOW_OFFSET_CONST 0x0002000000000000 # elif SANITIZER_WINDOWS64 # define ASAN_SHADOW_OFFSET_DYNAMIC # else diff --git a/compiler-rt/lib/asan/tests/asan_test.cpp b/compiler-rt/lib/asan/tests/asan_test.cpp index 827c2ae3a9cd..297812b7067b 100644 --- a/compiler-rt/lib/asan/tests/asan_test.cpp +++ b/compiler-rt/lib/asan/tests/asan_test.cpp @@ -631,7 +631,7 @@ NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) { #if !defined(__ANDROID__) && !defined(__arm__) && !defined(__aarch64__) && \ !defined(__mips__) && !defined(__mips64) && !defined(__s390__) && \ - !defined(__riscv) && !defined(__loongarch__) + !defined(__riscv) && !defined(__loongarch__) && !defined(__sw_64__) NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) { // create three red zones for these two stack objects. int a; @@ -656,7 +656,8 @@ TEST(AddressSanitizer, BuiltinLongJmpTest) { #endif // !defined(__ANDROID__) && !defined(__arm__) && // !defined(__aarch64__) && !defined(__mips__) && // !defined(__mips64) && !defined(__s390__) && - // !defined(__riscv) && !defined(__loongarch__) + // !defined(__riscv) && !defined(__loongarch__) && + // !defined(__sw_64__) TEST(AddressSanitizer, UnderscopeLongJmpTest) { static jmp_buf buf; diff --git a/compiler-rt/lib/fuzzer/FuzzerPlatform.h b/compiler-rt/lib/fuzzer/FuzzerPlatform.h index 1602e6789500..33ff503de01d 100644 --- a/compiler-rt/lib/fuzzer/FuzzerPlatform.h +++ b/compiler-rt/lib/fuzzer/FuzzerPlatform.h @@ -87,6 +87,10 @@ (LIBFUZZER_APPLE || LIBFUZZER_LINUX || LIBFUZZER_NETBSD || \ LIBFUZZER_FREEBSD || LIBFUZZER_EMSCRIPTEN) +#ifdef __sw_64__ +#define LIBFUZZER_SW64 1 +#endif + #ifdef __x86_64 #if __has_attribute(target) #define ATTRIBUTE_TARGET_POPCNT __attribute__((target("popcnt"))) diff --git a/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp b/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp index 7f4e8ef91c44..01927162d7b9 100644 --- a/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp @@ -150,7 +150,7 @@ ALWAYS_INLINE uintptr_t TracePC::GetNextInstructionPc(uintptr_t PC) { #if defined(__mips__) return PC + 8; #elif defined(__powerpc__) || defined(__sparc__) || defined(__arm__) || \ - defined(__aarch64__) || defined(__loongarch__) + defined(__aarch64__) || defined(__loongarch__) || defined(__sw_64__) return PC + 4; #else return PC + 1; diff --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp index 12d579a9385b..0aa2b1684496 100644 --- a/compiler-rt/lib/lsan/lsan_allocator.cpp +++ b/compiler-rt/lib/lsan/lsan_allocator.cpp @@ -28,7 +28,7 @@ extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { #if defined(__i386__) || defined(__arm__) static const uptr kMaxAllowedMallocSize = 1ULL << 30; -#elif defined(__mips64) || defined(__aarch64__) +#elif defined(__mips64) || defined(__aarch64__) || defined(__sw_64__) static const uptr kMaxAllowedMallocSize = 4ULL << 30; #else static const uptr kMaxAllowedMallocSize = 8ULL << 30; diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp index 9b73ddbdc756..6bcf1bb66898 100644 --- a/compiler-rt/lib/lsan/lsan_common.cpp +++ b/compiler-rt/lib/lsan/lsan_common.cpp @@ -279,6 +279,8 @@ static inline bool MaybeUserPointer(uptr p) { # elif defined(__loongarch_lp64) // Allow 47-bit user-space VMA at current. return ((p >> 47) == 0); +# elif defined(__sw_64__) + return ((p >> 52) == 0); # else return true; # endif diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h index d3e768363e93..7013f8135366 100644 --- a/compiler-rt/lib/lsan/lsan_common.h +++ b/compiler-rt/lib/lsan/lsan_common.h @@ -48,6 +48,8 @@ # define CAN_SANITIZE_LEAKS 1 #elif SANITIZER_RISCV64 && SANITIZER_LINUX # define CAN_SANITIZE_LEAKS 1 +#elif defined(__sw_64__) && SANITIZER_LINUX +# define CAN_SANITIZE_LEAKS 1 #elif SANITIZER_NETBSD || SANITIZER_FUCHSIA # define CAN_SANITIZE_LEAKS 1 #else diff --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h index b3a9c641b4fb..1b4b25a3ad16 100644 --- a/compiler-rt/lib/msan/msan.h +++ b/compiler-rt/lib/msan/msan.h @@ -212,6 +212,18 @@ const MappingDesc kMemoryLayout[] = { #define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x500000000000ULL) #define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x100000000000ULL) +#elif SANITIZER_LINUX && defined(__sw_64__) +const MappingDesc kMemoryLayout[] = { + {0x0000000000000ULL, 0x0100000000000ULL, MappingDesc::APP, "low memory"}, + {0x0100000000000ULL, 0x0400000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0400000000000ULL, 0x1000000000000ULL, MappingDesc::APP, "high memory"}, + {0x1000000000000ULL, 0x2000000000000ULL, MappingDesc::SHADOW, "shadow"}, + {0x2000000000000ULL, 0x5000000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x5000000000000ULL, 0x6000000000000ULL, MappingDesc::ORIGIN, "origin"}}; + +#define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x1000000000000ULL) +#define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x4000000000000ULL) + #else #error "Unsupported platform" #endif diff --git a/compiler-rt/lib/msan/msan_allocator.cpp b/compiler-rt/lib/msan/msan_allocator.cpp index c3b0f8512e82..5b5f7cbccfe3 100644 --- a/compiler-rt/lib/msan/msan_allocator.cpp +++ b/compiler-rt/lib/msan/msan_allocator.cpp @@ -139,6 +139,20 @@ struct AP64 { using AddressSpaceView = LocalAddressSpaceView; }; typedef SizeClassAllocator64 PrimaryAllocator; +#elif defined(__sw_64__) +static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G + +struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = sizeof(Metadata); + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = 20; + using AddressSpaceView = LocalAddressSpaceView; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; +typedef SizeClassAllocator32 PrimaryAllocator; #endif typedef CombinedAllocator Allocator; typedef Allocator::AllocatorCache AllocatorCache; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_asm.h b/compiler-rt/lib/sanitizer_common/sanitizer_asm.h index 3c9bbdc9678b..31e4d68755cc 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_asm.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_asm.h @@ -67,7 +67,7 @@ # define ASM_SYMBOL(symbol) symbol # define ASM_SYMBOL_INTERCEPTOR(symbol) symbol # if defined(__i386__) || defined(__powerpc__) || defined(__s390__) || \ - defined(__sparc__) + defined(__sparc__) || defined(__sw_64__) // For details, see interception.h # define ASM_WRAPPER_NAME(symbol) __interceptor_##symbol # define ASM_TRAMPOLINE_ALIAS(symbol, name) \ diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 0e563fa12022..0e2eda738ec7 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -4711,7 +4711,12 @@ INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) { } return res; } +// SW64 calls shmctl@@GLIBC_2.2 while common interceptor calls shmctl@GLIBC_2.0 +#if SANITIZER_SW64 +#define INIT_SHMCTL COMMON_INTERCEPT_FUNCTION_VER(shmctl, "GLIBC_2.2"); +#else #define INIT_SHMCTL COMMON_INTERCEPT_FUNCTION(shmctl); +#endif #else #define INIT_SHMCTL #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc index c10943b3e487..1b80d0d7432c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc @@ -2516,7 +2516,7 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { # if !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \ - defined(__loongarch__) || SANITIZER_RISCV64) + defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sw_64__)) if (data) { if (request == ptrace_setregs) { PRE_READ((void *)data, struct_user_regs_struct_sz); @@ -2538,7 +2538,7 @@ POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) { # if !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \ - defined(__loongarch__) || SANITIZER_RISCV64) + defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sw_64__)) if (res >= 0 && data) { // Note that this is different from the interceptor in // sanitizer_common_interceptors.inc. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index d2b3b63f3a7a..6aca7e0b2332 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -50,6 +50,14 @@ #undef stat #endif +#if defined(__sw_64__) +#define stat kernel_stat +#define stat64 kernel_stat64 +#include +#undef stat +#undef stat64 +#endif + #include #include #include @@ -322,7 +330,7 @@ static void statx_to_stat(struct statx *in, struct stat *out) { } #endif -#if SANITIZER_MIPS64 +#if SANITIZER_MIPS64 || SANITIZER_SW64 // Undefine compatibility macros from // so that they would not clash with the kernel_stat // st_[a|m|c]time fields @@ -352,6 +360,12 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { out->st_size = in->st_size; out->st_blksize = in->st_blksize; out->st_blocks = in->st_blocks; +#if defined(__sw_64__) + // There's no nsecs in sw_64's struct stat + out->st_atim.tv_sec = in->st_atime; + out->st_mtim.tv_sec = in->st_mtime; + out->st_ctim.tv_sec = in->st_ctime; +#else #if defined(__USE_MISC) || \ defined(__USE_XOPEN2K8) || \ defined(SANITIZER_ANDROID) @@ -369,6 +383,7 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { out->st_ctime = in->st_ctime; out->st_atimensec = in->st_ctime_nsec; #endif +#endif } #endif @@ -382,6 +397,11 @@ uptr internal_stat(const char *path, void *buf) { AT_NO_AUTOMOUNT, STATX_BASIC_STATS, (uptr)&bufx); statx_to_stat(&bufx, (struct stat *)buf); return res; +# elif defined(__sw_64__) + struct kernel_stat kbuf; + int res = internal_syscall(SYSCALL(stat), path, &kbuf); + kernel_stat_to_stat(&kbuf, (struct stat *)buf); + return res; # elif (SANITIZER_WORDSIZE == 64 || SANITIZER_X32 || \ (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \ !SANITIZER_SPARC @@ -414,6 +434,11 @@ uptr internal_lstat(const char *path, void *buf) { STATX_BASIC_STATS, (uptr)&bufx); statx_to_stat(&bufx, (struct stat *)buf); return res; +# elif SANITIZER_SW64 + struct kernel_stat kbuf; + int res = internal_syscall(SYSCALL(lstat), path, &kbuf); + kernel_stat_to_stat(&kbuf, (struct stat *)buf); + return res; # elif (defined(_LP64) || SANITIZER_X32 || \ (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \ !SANITIZER_SPARC @@ -436,7 +461,7 @@ uptr internal_lstat(const char *path, void *buf) { uptr internal_fstat(fd_t fd, void *buf) { #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS -#if SANITIZER_MIPS64 +#if SANITIZER_MIPS64 || SANITIZER_SW64 // For mips64, fstat syscall fills buffer in the format of kernel_stat struct kernel_stat kbuf; int res = internal_syscall(SYSCALL(fstat), fd, &kbuf); @@ -780,6 +805,15 @@ uptr internal_waitpid(int pid, int *status, int options) { 0 /* rusage */); } +#if SANITIZER_SW64 // FIXME +uptr internal_getpid() { + return internal_syscall(SYSCALL(getxpid)); +} + +uptr internal_getppid() { + return internal_syscall(SYSCALL(getppid)); +} +#else uptr internal_getpid() { return internal_syscall(SYSCALL(getpid)); } @@ -787,6 +821,7 @@ uptr internal_getpid() { uptr internal_getppid() { return internal_syscall(SYSCALL(getppid)); } +#endif int internal_dlinfo(void *handle, int request, void *p) { #if SANITIZER_FREEBSD @@ -899,7 +934,7 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { // rt_sigaction, so we need to do the same (we'll need to reimplement the // restorers; for x86_64 the restorer address can be obtained from // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact). -#if !SANITIZER_ANDROID || !SANITIZER_MIPS32 +#if (!SANITIZER_ANDROID || !SANITIZER_MIPS32) && !SANITIZER_SW64 k_act.sa_restorer = u_act->sa_restorer; #endif } @@ -915,7 +950,7 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask, sizeof(__sanitizer_kernel_sigset_t)); u_oldact->sa_flags = k_oldact.sa_flags; -#if !SANITIZER_ANDROID || !SANITIZER_MIPS32 +#if (!SANITIZER_ANDROID || !SANITIZER_MIPS32) && !SANITIZER_SW64 u_oldact->sa_restorer = k_oldact.sa_restorer; #endif } @@ -1123,6 +1158,10 @@ uptr GetMaxVirtualAddress() { return (1ULL << 38) - 1; # elif SANITIZER_MIPS64 return (1ULL << 40) - 1; // 0x000000ffffffffffUL; +# elif defined(__sw_64__) + // sw6b has a 52-bit user address space(4PiB) with 4-level pagetable + // according to TASK_SIZE in kernel. + return (1ULL << 52) - 1; // 0x000fffffffffffffUL; # elif defined(__s390x__) return (1ULL << 53) - 1; // 0x001fffffffffffffUL; #elif defined(__sparc__) @@ -1455,6 +1494,71 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, : "memory"); return res; } +#elif defined(__sw_64__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; + if (!fn || !child_stack) + return -EINVAL; + child_stack = (char *)child_stack - 4 * sizeof(unsigned long long); + ((unsigned long long *)child_stack)[0] = (uptr)fn; + ((unsigned long long *)child_stack)[1] = (uptr)arg; + ((unsigned long long *)child_stack)[2] = (uptr)flags; + + register void *r20 __asm__("$20") = newtls; + register int *r22 __asm__("$22") = child_tidptr; + + __asm__ __volatile__( + /* $v0 = syscall($v0 = __NR_clone, + * $a0 = flags, + * $a1 = child_stack, + * $a2 = parent_tidptr, + * $a3 = child_tidptr, + * $a4 = new_tls) + */ + "mov %[flag],$16\n" + "mov %[usp],$17\n" + "mov %[ptid],$18\n" + "ldl $19,0($sp)\n" + "mov %5,$20\n" + /* Store the fifth argument on stack + * if we are using 32-bit abi. + */ + "ldi $0,%[NR_clone];\n" + "sys_call 0x83;\n" + + /* if ($v0 != 0) + * return; + */ + "bne $0,1f;\n" + "mov $31,$15;\n" + /* Call "fn(arg)". */ + "ldl $27,0($sp);\n" + "ldl $16,8($sp);\n" + "ldi $sp,32($sp);\n" + + "call $26,($27),0;\n" + "ldgp $29, 0($26);\n" + + /* Call _exit($v0). */ + "mov $0,$16;\n" + "ldi $0,%[NR_exit];\n" + "sys_call 0x83;\n" + + /* Return to parent. */ + "1:\n" + : "=r" (res) + : [flag]"r"(flags), + [usp]"r"(child_stack), + [ptid]"r"(parent_tidptr), + "r"(r20), + "r"(r22), + [NR_clone]"i"(__NR_clone), + [NR_exit]"i"(__NR_exit) + : "memory", "$30" ); + + return res; +} #elif defined(__aarch64__) uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { @@ -2008,6 +2112,65 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const { if (flags & SC_ADDRERR_WR) return SignalContext::Write; return SignalContext::Unknown; +#elif defined(__sw_64__) + uint32_t *exception_source; + uint32_t faulty_instruction; + uint32_t op_code; + + exception_source = (uint32_t *)ucontext->uc_mcontext.sc_pc; + faulty_instruction = (uint32_t)(*exception_source); + + op_code = (faulty_instruction >> 26) & 0x3f; + + switch (op_code) { + case 0x28: // STB + case 0x29: // STH + case 0x2A: // STW + case 0x2B: // STL + case 0x2C: // STL_U + case 0x2E: // FSTS + case 0x2F: // FSTD + case 0x0E: // VSTS + case 0x0F: // STD + return SignalContext::Write; + + case 0x20: // LDBU + case 0x21: // LDHU + case 0x22: // LDW + case 0x23: // LDL + case 0x24: // LDL_U + case 0x26: // FLDS + case 0x27: // FLDD + case 0x09: // LDWE + case 0x0A: // LDSE + case 0x0B: // LDDE + case 0x0C: // VLDS + case 0x0D: // VLDD + return SignalContext::Read; + + case 0x1C: // SIMD + op_code = (faulty_instruction >> 12) & 0x3; + switch (op_code) { + case 0x1: // VSTW_U + case 0x3: // VSTS_U + case 0x5: // VSTD_U + case 0x8: // VSTW_UL + case 0x9: // VSTW_UH + case 0xA: // VSTS_UL + case 0xB: // VSTS_UH + case 0xC: // VSTD_UL + case 0xD: // VSTD_UH + case 0xF: // VSTD_NC + return SignalContext::Write; + + case 0x0: // VLDW_U + case 0x2: // VLDS_U + case 0x4: // VLDD_U + case 0xE: // VLDD_NC + return SignalContext::Read; + } + } + return SignalContext::Unknown; #elif defined(__sparc__) // Decode the instruction to determine the access type. // From OpenSolaris $SRC/uts/sun4/os/trap.c (get_accesstype). @@ -2251,6 +2414,11 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { *pc = ucontext->uc_mcontext.pc; *bp = ucontext->uc_mcontext.gregs[30]; *sp = ucontext->uc_mcontext.gregs[29]; +#elif defined(__sw_64__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.sc_pc; + *bp = ucontext->uc_mcontext.sc_regs[15]; + *sp = ucontext->uc_mcontext.sc_regs[30]; #elif defined(__s390__) ucontext_t *ucontext = (ucontext_t*)context; # if defined(__s390x__) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h index 7454369fa419..401a5b485e21 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h @@ -80,7 +80,8 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact); void internal_sigdelset(__sanitizer_sigset_t *set, int signum); # if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \ defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \ - defined(__arm__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64 + defined(__arm__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64 || \ + defined(__sw_64__) uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr); #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp index 42013f471870..4e254825c8f5 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp @@ -206,7 +206,7 @@ void InitTlsSize() { GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25; #if defined(__aarch64__) || defined(__x86_64__) || defined(__powerpc64__) || \ - defined(__loongarch__) + defined(__loongarch__) || defined(__sw_64__) void *get_tls_static_info = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); size_t tls_align; ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align); @@ -288,6 +288,8 @@ static uptr ThreadDescriptorSizeFallback() { val = 1776; #elif defined(__powerpc64__) val = 1776; // from glibc.ppc64le 2.20-8.fc21 +#elif defined(__sw_64__) + val = 1776; #endif return val; } @@ -522,6 +524,10 @@ static void GetTls(uptr *addr, uptr *size) { const uptr pre_tcb_size = TlsPreTcbSize(); *addr = tp - pre_tcb_size; *size = g_tls_size + pre_tcb_size; +#elif SANITIZER_GLIBC && defined(__sw_64__) + *addr = reinterpret_cast(__builtin_thread_pointer()) - + ThreadDescriptorSize(); + *size = g_tls_size + ThreadDescriptorSize(); #elif SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_SOLARIS uptr align; GetStaticTlsBoundary(addr, size, &align); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h index 764996e57355..9e7ae480cdf6 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h @@ -278,6 +278,12 @@ # define SANITIZER_LOONGARCH64 0 #endif +#if defined(__sw_64__) +# define SANITIZER_SW64 1 +#else +# define SANITIZER_SW64 0 +#endif + // By default we allow to use SizeClassAllocator64 on 64-bit platform. // But in some cases SizeClassAllocator64 does not work well and we need to // fallback to SizeClassAllocator32. @@ -319,6 +325,8 @@ # endif #elif defined(__sparc__) # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 52) +#elif defined(__sw_64__) +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 52) #else # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47) #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index c740778b6228..a36ebaa18340 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -233,8 +233,15 @@ (SI_LINUX || SI_FREEBSD || SI_NETBSD) #define SANITIZER_INTERCEPT_GETITIMER SI_POSIX #define SANITIZER_INTERCEPT_TIME SI_POSIX +// Disable the glob intercept as SW64 calls glob64 actually when glob is used. +// Hacking it like glibc is a better way, which is difficult. +#if SANITIZER_SW64 +#define SANITIZER_INTERCEPT_GLOB 0 +#define SANITIZER_INTERCEPT_GLOB64 0 +#else #define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS) #define SANITIZER_INTERCEPT_GLOB64 SI_GLIBC +#endif #define SANITIZER_INTERCEPT___B64_TO SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_DN_COMP_EXPAND SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_POSIX_SPAWN SI_POSIX @@ -273,7 +280,8 @@ #if SI_LINUX_NOT_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64) + defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 || \ + defined(__sw_64__)) #define SANITIZER_INTERCEPT_PTRACE 1 #else #define SANITIZER_INTERCEPT_PTRACE 0 diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_linux.cpp index bf0f355847cb..a5cc85809cb9 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_linux.cpp @@ -60,7 +60,7 @@ using namespace __sanitizer; # if !defined(__powerpc64__) && !defined(__x86_64__) && \ !defined(__aarch64__) && !defined(__mips__) && !defined(__s390__) && \ !defined(__sparc__) && !defined(__riscv) && !defined(__hexagon__) && \ - !defined(__loongarch__) + !defined(__loongarch__) && !defined(__sw_64__) COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat)); #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp index 6d61d276d77e..5e521126c5fd 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -95,7 +95,8 @@ # include # include # if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \ - defined(__hexagon__) || defined(__loongarch__) ||SANITIZER_RISCV64 + defined(__hexagon__) || defined(__loongarch__) ||SANITIZER_RISCV64 || \ + defined(__sw_64__) # include # ifdef __arm__ typedef struct user_fpregs elf_fpregset_t; @@ -142,7 +143,7 @@ typedef struct user_fpregs elf_fpregset_t; #include #include #include -#if defined(__mips64) +#if defined(__mips64) || defined(__sw_64__) # include #endif #include @@ -278,7 +279,7 @@ namespace __sanitizer { // has been removed from glibc 2.28. #if defined(__aarch64__) || defined(__s390x__) || defined(__mips64) || \ defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) || \ - defined(__x86_64__) || SANITIZER_RISCV64 + defined(__x86_64__) || SANITIZER_RISCV64 || defined(__sw_64__) #define SIZEOF_STRUCT_USTAT 32 # elif defined(__arm__) || defined(__i386__) || defined(__mips__) || \ defined(__powerpc__) || defined(__s390__) || defined(__sparc__) || \ @@ -361,7 +362,8 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__) || defined(__loongarch__)|| SANITIZER_RISCV64) + defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 || \ + defined(__sw_64__)) #if defined(__mips64) || defined(__powerpc64__) || defined(__arm__) unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs); unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t); @@ -374,6 +376,9 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); #elif defined(__loongarch__) unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs); unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fp_state); +#elif defined(__sw_64__) + unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs); + unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state); #elif defined(__s390__) unsigned struct_user_regs_struct_sz = sizeof(struct _user_regs_struct); unsigned struct_user_fpregs_struct_sz = sizeof(struct _user_fpregs_struct); @@ -383,7 +388,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); #endif // __mips64 || __powerpc64__ || __aarch64__ || __loongarch__ #if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \ defined(__aarch64__) || defined(__arm__) || defined(__s390__) || \ - defined(__loongarch__) || SANITIZER_RISCV64 + defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sw_64__) unsigned struct_user_fpxregs_struct_sz = 0; #else unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct); @@ -1130,7 +1135,8 @@ CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); // didn't exist. CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); #endif -#if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32) +#if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32) && \ + !SANITIZER_SW64 CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer); #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 58244c9944a0..aa616855db76 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -117,6 +117,9 @@ const unsigned struct_kernel_stat64_sz = 144; const unsigned struct___old_kernel_stat_sz = 0; const unsigned struct_kernel_stat_sz = 64; const unsigned struct_kernel_stat64_sz = 104; +#elif defined(__sw_64__) +const unsigned struct_kernel_stat_sz = 80; +const unsigned struct_kernel_stat64_sz = 136; #elif SANITIZER_RISCV64 const unsigned struct_kernel_stat_sz = 128; const unsigned struct_kernel_stat64_sz = 0; // RISCV64 does not use stat64 @@ -274,15 +277,15 @@ struct __sanitizer_shmid_ds { u64 shm_ctime; #else uptr shm_atime; -#if !defined(_LP64) && !defined(__mips__) +#if !defined(_LP64) && !defined(__mips__) && !defined(__sw_64__) uptr __unused1; #endif uptr shm_dtime; -#if !defined(_LP64) && !defined(__mips__) +#if !defined(_LP64) && !defined(__mips__) && !defined(__sw_64__) uptr __unused2; #endif uptr shm_ctime; -#if !defined(_LP64) && !defined(__mips__) +#if !defined(_LP64) && !defined(__mips__) && !defined(__sw_64__) uptr __unused3; #endif #endif @@ -527,7 +530,7 @@ typedef int __sanitizer_clockid_t; #if SANITIZER_LINUX # if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) || \ - defined(__mips__) || defined(__hexagon__) + defined(__mips__) || defined(__hexagon__) || defined(__sw_64__) typedef unsigned __sanitizer___kernel_uid_t; typedef unsigned __sanitizer___kernel_gid_t; #else @@ -540,7 +543,7 @@ typedef long long __sanitizer___kernel_off_t; typedef long __sanitizer___kernel_off_t; #endif -#if defined(__powerpc__) || defined(__mips__) +#if defined(__powerpc__) || defined(__mips__) || defined(__sw_64__) typedef unsigned int __sanitizer___kernel_old_uid_t; typedef unsigned int __sanitizer___kernel_old_gid_t; #else @@ -677,7 +680,7 @@ struct __sanitizer_sigaction { #endif #endif #endif -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !defined(__sw_64__) void (*sa_restorer)(); #endif #if defined(__mips__) && (SANITIZER_WORDSIZE == 32) @@ -857,7 +860,8 @@ typedef void __sanitizer_FILE; #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64) + defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 || \ + defined(__sw_64__)) extern unsigned struct_user_regs_struct_sz; extern unsigned struct_user_fpregs_struct_sz; extern unsigned struct_user_fpxregs_struct_sz; @@ -943,7 +947,7 @@ struct __sanitizer_cookie_io_functions_t { #define IOC_NRBITS 8 #define IOC_TYPEBITS 8 #if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) || \ - defined(__sparc__) + defined(__sparc__) || defined(__sw_64__) #define IOC_SIZEBITS 13 #define IOC_DIRBITS 3 #define IOC_NONE 1U diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h index 47aed488c71a..4474c455523f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h @@ -24,6 +24,8 @@ static const u32 kStackTraceMax = 255; #if SANITIZER_LINUX && defined(__mips__) # define SANITIZER_CAN_FAST_UNWIND 0 +#elif SANITIZER_LINUX && defined(__sw_64__) +# define SANITIZER_CAN_FAST_UNWIND 0 #elif SANITIZER_WINDOWS # define SANITIZER_CAN_FAST_UNWIND 0 #else diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp index 13b90ce9bf51..f68935ac4a5f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp @@ -16,7 +16,8 @@ #if SANITIZER_LINUX && \ (defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \ defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \ - defined(__arm__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64) + defined(__arm__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64 || \ + defined(__sw_64__)) #include "sanitizer_stoptheworld.h" @@ -509,6 +510,12 @@ typedef struct user regs_struct; # define REG_SP regs[EF_REG29] # endif +#elif defined(__sw_64__) +typedef struct user regs_struct; +#define REG_SP regs[30] +static constexpr uptr kExtraRegs[] = {0}; +#define ARCH_IOVEC_FOR_GETREGSET + #elif defined(__aarch64__) typedef struct user_pt_regs regs_struct; #define REG_SP sp diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp index a6f82ced2036..efa870b9bc3f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp @@ -272,6 +272,8 @@ class LLVMSymbolizerProcess final : public SymbolizerProcess { const char* const kSymbolizerArch = "--default-arch=s390x"; #elif defined(__s390__) const char* const kSymbolizerArch = "--default-arch=s390"; +#elif defined(__sw_64__) + const char* const kSymbolizerArch = "--default-arch=sw_64"; #else const char* const kSymbolizerArch = "--default-arch=unknown"; #endif diff --git a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt index c6f6633b99e2..480e1593d1b2 100644 --- a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt @@ -3,7 +3,7 @@ include(CompilerRTCompile) clang_compiler_add_cxx_check() # FIXME: use SANITIZER_COMMON_SUPPORTED_ARCH here -filter_available_targets(SANITIZER_UNITTEST_SUPPORTED_ARCH x86_64 i386 mips64 mips64el riscv64 sparcv9 sparc) +filter_available_targets(SANITIZER_UNITTEST_SUPPORTED_ARCH x86_64 i386 mips64 mips64el riscv64 sparcv9 sparc sw_64) if(APPLE) list(APPEND SANITIZER_UNITTEST_SUPPORTED_ARCH arm64) darwin_filter_host_archs(SANITIZER_UNITTEST_SUPPORTED_ARCH SANITIZER_UNITTEST_SUPPORTED_ARCH) diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cpp index 58f2c8f7b333..d66ccc0e51e1 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cpp @@ -162,6 +162,8 @@ static const u64 kAddressSpaceSize = 1ULL << 39; static const u64 kAddressSpaceSize = 1ULL << 53; #elif defined(__s390__) static const u64 kAddressSpaceSize = 1ULL << 31; +#elif defined(__sw_64__) +static const u64 kAddressSpaceSize = 1ULL << 52; #else static const u64 kAddressSpaceSize = 1ULL << 32; #endif diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cpp index 8da09f693c2b..6c33f0fca47c 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cpp @@ -77,7 +77,11 @@ TEST(SanitizerIoctl, Fixup) { // Test decoding KVM ioctl numbers. TEST(SanitizerIoctl, KVM_GET_MP_STATE) { ioctl_desc desc; +#ifndef __sw_64__ unsigned int desc_value = SANITIZER_MIPS ? 0x4004ae98U : 0x8004ae98U; +#else + unsigned int desc_value = SANITIZER_SW64 ? 0x4004ae98U : 0x8004ae98U; +#endif bool res = ioctl_decode(desc_value, &desc); EXPECT_TRUE(res); EXPECT_EQ(ioctl_desc::WRITE, desc.type); @@ -86,7 +90,11 @@ TEST(SanitizerIoctl, KVM_GET_MP_STATE) { TEST(SanitizerIoctl, KVM_GET_LAPIC) { ioctl_desc desc; +#ifndef __sw_64__ unsigned int desc_value = SANITIZER_MIPS ? 0x4400ae8eU : 0x8400ae8eU; +#else + unsigned int desc_value = SANITIZER_SW64 ? 0x4400ae8eU : 0x8400ae8eU; +#endif bool res = ioctl_decode(desc_value, &desc); EXPECT_TRUE(res); EXPECT_EQ(ioctl_desc::WRITE, desc.type); diff --git a/compiler-rt/lib/tsan/rtl/CMakeLists.txt b/compiler-rt/lib/tsan/rtl/CMakeLists.txt index 4107e04b87d8..6a4c0e085fce 100644 --- a/compiler-rt/lib/tsan/rtl/CMakeLists.txt +++ b/compiler-rt/lib/tsan/rtl/CMakeLists.txt @@ -220,6 +220,10 @@ else() set(TSAN_ASM_SOURCES tsan_rtl_mips64.S ) + elseif(arch MATCHES "sw_64|sw64") + set(TSAN_ASM_SOURCES + tsan_rtl_sw64.S + ) elseif(arch MATCHES "s390x") set(TSAN_ASM_SOURCES tsan_rtl_s390x.S diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp index 622afc90a577..92393a59ea6c 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp @@ -76,7 +76,7 @@ struct ucontext_t { #endif #if defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 || \ - defined(__s390x__) + defined(__s390x__) || defined(__sw_64__) #define PTHREAD_ABI_BASE "GLIBC_2.3.2" #elif defined(__aarch64__) || SANITIZER_PPC64V2 #define PTHREAD_ABI_BASE "GLIBC_2.17" @@ -151,7 +151,7 @@ typedef __sanitizer::u16 mode_t; # define F_TLOCK 2 /* Test and lock a region for exclusive use. */ # define F_TEST 3 /* Test a region for other processes locks. */ -#if SANITIZER_FREEBSD || SANITIZER_APPLE || SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_APPLE || SANITIZER_NETBSD || SANITIZER_SW64 const int SA_SIGINFO = 0x40; const int SIG_SETMASK = 3; #elif defined(__mips__) @@ -2567,7 +2567,8 @@ int sigaction_impl(int sig, const __sanitizer_sigaction *act, sigactions[sig].sa_flags = *(volatile int const *)&act->sa_flags; internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask, sizeof(sigactions[sig].sa_mask)); -#if !SANITIZER_FREEBSD && !SANITIZER_APPLE && !SANITIZER_NETBSD +#if !SANITIZER_FREEBSD && !SANITIZER_APPLE && !SANITIZER_NETBSD && \ + !SANITIZER_SW64 sigactions[sig].sa_restorer = act->sa_restorer; #endif internal_memcpy(&newact, act, sizeof(newact)); @@ -2870,7 +2871,11 @@ void InitializeInterceptors() { TSAN_INTERCEPT(strncpy); TSAN_INTERCEPT(strdup); + #if SANITIZER_SW64 + TSAN_INTERCEPT_VER(pthread_create, "GLIBC_2.1"); + #else TSAN_INTERCEPT(pthread_create); + #endif TSAN_INTERCEPT(pthread_join); TSAN_INTERCEPT(pthread_detach); TSAN_INTERCEPT(pthread_exit); @@ -2879,6 +2884,14 @@ void InitializeInterceptors() { TSAN_INTERCEPT(pthread_timedjoin_np); #endif + #if SANITIZER_SW64 + // sw64 have two version of timer function, osf_xxx with @glibc2.0, + // which is 32bits syscall for old kernal. xxx with @glibc2.1 is 64bits + // syscall for new kernal, we use the new one. + TSAN_INTERCEPT_VER(setitimer, "GLIBC_2.1"); + TSAN_INTERCEPT_VER(getitimer, "GLIBC_2.1"); + #endif + TSAN_INTERCEPT_VER(pthread_cond_init, PTHREAD_ABI_BASE); TSAN_INTERCEPT_VER(pthread_cond_signal, PTHREAD_ABI_BASE); TSAN_INTERCEPT_VER(pthread_cond_broadcast, PTHREAD_ABI_BASE); diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface.h b/compiler-rt/lib/tsan/rtl/tsan_interface.h index d53c1e3935df..6e25f2c5e481 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interface.h +++ b/compiler-rt/lib/tsan/rtl/tsan_interface.h @@ -209,7 +209,7 @@ typedef unsigned int a32; typedef unsigned long long a64; #if !SANITIZER_GO && (defined(__SIZEOF_INT128__) \ || (__clang_major__ * 100 + __clang_minor__ >= 302)) && \ - !defined(__mips64) && !defined(__s390x__) + !defined(__mips64) && !defined(__s390x__) && !defined(__sw_64__) __extension__ typedef __int128 a128; # define __TSAN_HAS_INT128 1 #else diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform.h b/compiler-rt/lib/tsan/rtl/tsan_platform.h index 48dd56d15751..38ccc680d5b9 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_platform.h +++ b/compiler-rt/lib/tsan/rtl/tsan_platform.h @@ -644,6 +644,46 @@ struct MappingGoS390x { static const uptr kShadowAdd = 0x400000000000ull; }; +// TODO(sw64_map): as sw64 kernal doesn't map such large space, we just map +// it for test, for now it works will. +// TODO(sw64_map_la): as sw64 map all space in low address, we set all user +// space +// in Lo address, perhaps there is some way to change it. +/* +C/C++ on linux/sw64 (52-bit VMA) +0000 0000 0000 - 0001 2000 0000: modules and main thread stack +0001 2000 0000 - 0008 0000 0000: main binary +0400 0000 0000 - 0600 0000 0000: pie main binary (including heap) +0600 0000 0000 - 4000 0000 0000: - +4000 0000 0000 - 6000 0000 0000: shadow +6000 0000 0000 - 7000 0000 0000: metainfo +7000 0000 0000 - 7c00 0000 0000: trace +*/ + +// TODO: fix HiAppMemEnd +struct MappingSW64 { + static const uptr kLoAppMemBeg = 0x0000000000000ull; + static const uptr kLoAppMemEnd = 0x0600000000000ull; + static const uptr kShadowBeg = 0x6000000000000ull; + static const uptr kShadowEnd = 0x8000000000000ull; + static const uptr kMidAppMemBeg = 0; + static const uptr kMidAppMemEnd = 0; + static const uptr kHiAppMemBeg = 0xfff7000000000ull; + static const uptr kHiAppMemEnd = 0x10000000000000ull; + static const uptr kShadowMsk = 0xf800000000000ull; + //distans between lo address to shadow begin + static const uptr kShadowXor = 0x1800000000000ull; + static const uptr kShadowAdd = 0x0ull; + static const uptr kHeapMemBeg = 0xff00000000000ull; + static const uptr kHeapMemEnd = 0xff00000000000ull; + static const uptr kMetaShadowBeg = 0x9000000000000ull; + static const uptr kMetaShadowEnd = 0xa000000000000ull; + +// static const uptr kTraceMemBeg = 0xa000000000000ull; +// static const uptr kTraceMemEnd = 0xac00000000000ull; + static const uptr kVdsoBeg = 0x3c00000000000000ull; +}; + extern uptr vmaSize; template @@ -698,6 +738,8 @@ ALWAYS_INLINE auto SelectMapping(Arg arg) { return Func::template Apply(arg); # elif defined(__s390x__) return Func::template Apply(arg); +# elif defined(__sw_64__) + return Func::template Apply(arg); # else # error "unsupported platform" # endif diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp index 3f4a3760794f..f2be3f7920ec 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp @@ -405,6 +405,10 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) { return mangled_sp ^ xor_key; #elif defined(__mips__) return mangled_sp; +#elif defined(__sw_64__) + uptr xor_key; + asm("ldl %0, __pointer_chk_guard($r29)" : "=r" (xor_key)); + return mangled_sp ^ xor_key; #elif defined(__s390x__) // tcbhead_t.stack_guard uptr xor_key = ((uptr *)__builtin_thread_pointer())[5]; @@ -437,6 +441,8 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) { # define LONG_JMP_SP_ENV_SLOT 1 # elif defined(__s390x__) # define LONG_JMP_SP_ENV_SLOT 9 +# elif defined(__sw_64__) +# define LONG_JMP_SP_ENV_SLOT 8 # else # define LONG_JMP_SP_ENV_SLOT 6 # endif diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h index a5606dbc7f88..665b51e124a5 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -57,7 +57,7 @@ namespace __tsan { #if !SANITIZER_GO struct MapUnmapCallback; #if defined(__mips64) || defined(__aarch64__) || defined(__loongarch__) || \ - defined(__powerpc__) + defined(__powerpc__) || defined(__sw_64__) struct AP32 { static const uptr kSpaceBeg = 0; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_sw64.S b/compiler-rt/lib/tsan/rtl/tsan_rtl_sw64.S new file mode 100644 index 000000000000..fd893a780385 --- /dev/null +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_sw64.S @@ -0,0 +1,233 @@ +// The content of this file is sw64-only: +#if defined(__sw_64__) + +#include "sanitizer_common/sanitizer_asm.h" + +.section .text +.set noreorder + +ASM_HIDDEN(__tsan_setjmp) +.comm _ZN14__interception11real_setjmpE,8,8 +.globl ASM_SYMBOL_INTERCEPTOR(setjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(setjmp)) +ASM_SYMBOL_INTERCEPTOR(setjmp): + ldgp $r29, 0($r27) + CFI_STARTPROC + + // Save frame/link register + ldi $sp, -32($sp) + stl $r26, 0($sp) + stl $fp, 8($sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (26, -32) + CFI_OFFSET (15, -24) + + // Adjust the SP for previous frame + ldi $fp,0($sp) + CFI_DEF_CFA_REGISTER (15) + + // Save env parameter + stl $r16, 16($sp) + CFI_OFFSET (0, -16) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + ldi $r16, 32($sp) + + // call tsan interceptor + //ldih $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !gprelhigh + //ldi $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !gprellow + ldl $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !literal + call $r26, ($r27), 0 + ldgp $r29, 0($r26) + + // Restore env parameter + ldl $r16, 16($sp) + CFI_RESTORE (0) + + // Restore frame/link register + ldl $fp, 8($sp) + ldl $r26, 0($sp) + CFI_RESTORE (15) + CFI_RESTORE (26) + CFI_DEF_CFA (31, 0) + ldi $sp, 32($sp) + + // tail jump to libc setjmp + ldl $r27, _ZN14__interception11real_setjmpE($r29) !literal + ldl $r27, 0($r27) + jmp $r31, ($r27) + + CFI_ENDPROC +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(setjmp)) + +ASM_HIDDEN(__tsan_setjmp) +.comm _ZN14__interception12real__setjmpE,8,8 +.globl ASM_SYMBOL_INTERCEPTOR(_setjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(_setjmp)) +ASM_SYMBOL_INTERCEPTOR(_setjmp): + ldgp $r29, 0($r27) + CFI_STARTPROC + + // Save frame/link register + ldi $sp, -32($sp) + stl $r26, 0($sp) + stl $fp, 8($sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (26, -32) + CFI_OFFSET (15, -24) + + // Adjust the SP for previous frame + ldi $fp,0($sp) + CFI_DEF_CFA_REGISTER (15) + + // Save env parameter + stl $r16, 16($sp) + CFI_OFFSET (0, -16) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + ldi $r16, 32($sp) + + // call tsan interceptor + //ldih $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !gprelhigh + //ldi $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !gprellow + ldl $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !literal + call $r26, ($r27), 0 + ldgp $r29, 0($r26) + + // Restore env parameter + ldl $r16, 16($sp) + CFI_RESTORE (0) + + // Restore frame/link register + ldl $fp, 8($sp) + ldl $r26, 0($sp) + CFI_RESTORE (15) + CFI_RESTORE (26) + CFI_DEF_CFA (31, 0) + ldi $sp, 32($sp) + + // tail jump to libc setjmp + ldl $r27, _ZN14__interception12real__setjmpE($r29) !literal + ldl $r27, 0($r27) + jmp $r31, ($r27) + + CFI_ENDPROC +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(_setjmp)) + +ASM_HIDDEN(__tsan_setjmp) +.comm _ZN14__interception14real_sigsetjmpE,8,8 +.globl ASM_SYMBOL_INTERCEPTOR(sigsetjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(sigsetjmp)) +ASM_SYMBOL_INTERCEPTOR(sigsetjmp): + ldgp $r29, 0($r27) + CFI_STARTPROC + + // Save frame/link register + ldi $sp, -32($sp) + stl $r26, 0($sp) + stl $fp, 8($sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (26, -32) + CFI_OFFSET (15, -24) + + // Adjust the SP for previous frame + ldi $fp,0($sp) + CFI_DEF_CFA_REGISTER (15) + + // Save env parameter + stl $r16, 16($sp) + stl $r17, 24($sp) + CFI_OFFSET (16, -16) + CFI_OFFSET (17, -8) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + ldi $r16, 32($sp) + + // call tsan interceptor + //ldih $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !gprelhigh + //ldi $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !gprellow + ldl $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !literal + call $r26, ($r27), 0 + ldgp $r29, 0($r26) + + // Restore env parameter + ldl $r16, 16($sp) + ldl $r17, 24($sp) + CFI_RESTORE (0) + CFI_RESTORE (1) + + // Restore frame/link register + ldl $fp, 8($sp) + ldl $r26, 0($sp) + CFI_RESTORE (15) + CFI_RESTORE (26) + CFI_DEF_CFA (31, 0) + ldi $sp, 32($sp) + + // tail jump to libc setjmp + ldl $r27, _ZN14__interception14real_sigsetjmpE($r29) !literal + ldl $r27, 0($r27) + jmp $r31, ($r27) + + CFI_ENDPROC +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(sigsetjmp)) + +ASM_HIDDEN(__tsan_setjmp) +.comm _ZN14__interception16real___sigsetjmpE,8,8 +.globl ASM_SYMBOL_INTERCEPTOR(__sigsetjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)) +ASM_SYMBOL_INTERCEPTOR(__sigsetjmp): + ldgp $r29, 0($r27) + CFI_STARTPROC + + // Save frame/link register + ldi $sp, -32($sp) + stl $r26, 0($sp) + stl $fp, 8($sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (26, -32) + CFI_OFFSET (15, -24) + + // Adjust the SP for previous frame + ldi $fp,0($sp) + CFI_DEF_CFA_REGISTER (15) + + // Save env parameter + stl $r16, 16($sp) + stl $r17, 24($sp) + CFI_OFFSET (16, -16) + CFI_OFFSET (17, -8) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + ldi $r16, 32($sp) + + // call tsan interceptor + //ldih $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !gprelhigh + //ldi $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !gprellow + ldl $r27, ASM_SYMBOL(__tsan_setjmp)($r29) !literal + call $r26, ($r27), 0 + ldgp $r29, 0($r26) + + // Restore env parameter + ldl $r16, 16($sp) + ldl $r17, 24($sp) + CFI_RESTORE (0) + CFI_RESTORE (1) + + // Restore frame/link register + ldl $fp, 8($sp) + ldl $r26, 0($sp) + CFI_RESTORE (15) + CFI_RESTORE (26) + CFI_DEF_CFA (31, 0) + ldi $sp, 32($sp) + + // tail jump to libc setjmp + ldl $r27, _ZN14__interception16real___sigsetjmpE($r29) !literal + ldl $r27, 0($r27) + jmp $r31, ($r27) + + CFI_ENDPROC +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)) + +#endif diff --git a/compiler-rt/lib/xray/CMakeLists.txt b/compiler-rt/lib/xray/CMakeLists.txt index cf7b5062aae3..cb90399e53c6 100644 --- a/compiler-rt/lib/xray/CMakeLists.txt +++ b/compiler-rt/lib/xray/CMakeLists.txt @@ -72,6 +72,11 @@ set(mips64el_SOURCES xray_trampoline_mips64.S ) +set(sw_64_SOURCES + xray_sw64.cpp + xray_trampoline_sw64.S + ) + set(powerpc64le_SOURCES xray_powerpc64.cpp xray_trampoline_powerpc64.cpp @@ -140,6 +145,7 @@ set(XRAY_ALL_SOURCE_FILES ${mipsel_SOURCES} ${mips64_SOURCES} ${mips64el_SOURCES} + ${sw_64_SOURCES} ${powerpc64le_SOURCES} ${XRAY_IMPL_HEADERS} ) diff --git a/compiler-rt/lib/xray/xray_interface.cpp b/compiler-rt/lib/xray/xray_interface.cpp index 5839043fcb93..6425e83a0d3e 100644 --- a/compiler-rt/lib/xray/xray_interface.cpp +++ b/compiler-rt/lib/xray/xray_interface.cpp @@ -56,6 +56,8 @@ static const int16_t cSledLength = 64; static const int16_t cSledLength = 8; #elif defined(__hexagon__) static const int16_t cSledLength = 20; +#elif defined(__sw_64__) +static const int16_t cSledLength = 76; #else #error "Unsupported CPU Architecture" #endif /* CPU architecture */ diff --git a/compiler-rt/lib/xray/xray_sw64.cpp b/compiler-rt/lib/xray/xray_sw64.cpp new file mode 100644 index 000000000000..1b5fc964e9f8 --- /dev/null +++ b/compiler-rt/lib/xray/xray_sw64.cpp @@ -0,0 +1,152 @@ +//===-- xray_Sw64.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 XRay, a dynamic runtime instrumentation system. +// +// Implementation of Sw64-specific routines (64-bit). +// +//===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_common.h" +#include "xray_defs.h" +#include "xray_interface_internal.h" +#include +#include + +extern "C" void __clear_cache(void *start, void *end); + +namespace __xray { + +// The machine codes for some instructions used in runtime patching. +enum class PatchOpcodes : uint32_t { + PO_BR = 0x13e00012, // br 0x90 +}; + +inline static bool patchSled(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled, + void (*TracingHook)()) XRAY_NEVER_INSTRUMENT { + // When |Enable| == true, + // We replace the following compile-time stub (sled): + // + // xray_sled_n: + // ldi $r27,76($r27) + // br $r31,68 + // 17 NOPs (68 bytes) + // + // With the following runtime patch: + // + // xray_sled_n: + // ldi sp,-24(sp) + // stl ra,0(sp) + // stl fp,8(sp) + // stl $r27,16(sp) + // clr $r27 + // ldih $r27,0($r27) + // ldi $r27,0($r27) + // slll $r27,0x20,$r27 + // ldih $r27,0($r27) + // ldi $r27,0($r27) + // clr $r16 + // ldih $r16,0($r16) + // ldi $r16,0($r16) + // call ra,($r27),0x2c + // ldl $r27,16(sp) + // ldl fp,8(sp) + // ldl ra,0(sp) + // ldi sp,24(sp) + // ldi $r27,76($r27) + // + // Replacement of the first 4-byte instruction should be the last and atomic + // operation, so that the user code which reaches the sled concurrently + // either jumps over the whole sled, or executes the whole sled when the + // latter is ready. + // + // When |Enable|==false, we set back the first instruction in the sled to be + // br $r31,72 + + uint32_t *FirstAddress = reinterpret_cast(Sled.address()); + uint32_t *CurAddress = FirstAddress; + if (Enable) { + uint32_t LoTracingHookAddr = + reinterpret_cast(TracingHook) & 0xffff; + uint32_t HiTracingHookAddr = + (reinterpret_cast(TracingHook + 0x8000) >> 16) & 0xffff; + uint32_t HigherTracingHookAddr = + (reinterpret_cast(TracingHook + 0x80008000) >> 32) & 0xffff; + uint32_t HighestTracingHookAddr = + (reinterpret_cast(TracingHook + 0x800080008000) >> 48) & + 0xffff; + uint32_t LoFunctionID = FuncId & 0xffff; + uint32_t HiFunctionID = ((FuncId + 0x8000) >> 16) & 0xffff; + + // CurAddress[0] = 0xfbdeffe8; // ldi sp,-24(sp) + CurAddress[1] = 0xaf5e0000; // stl ra,0(sp) + CurAddress[2] = 0xadfe0008; // stl fp,8(sp) + CurAddress[3] = 0xaf7e0010; // stl $r27,16(sp) + CurAddress[4] = 0x43ff075b; // clr $r27 + CurAddress[5] = 0xff7b0000 | HighestTracingHookAddr; // ldih $r27,0($r27) + CurAddress[6] = 0xfb7b0000 | HigherTracingHookAddr; // ldi $r27,0($r27) + CurAddress[7] = 0x4b64091b; // slll $r27,0x20,$r27 + CurAddress[8] = 0xff7b0000 | HiTracingHookAddr; // ldih $r27,0($r27) + CurAddress[9] = 0xfb7b0000 | LoTracingHookAddr; // ldi $r27,0($r27) + CurAddress[10] = 0x43ff0750; // clr $r16 + CurAddress[11] = 0xfe100000 | HiFunctionID; // ldih $r16,0($r16) + CurAddress[12] = 0xfa100000 | LoFunctionID; // ldi $r16,0($r16) + CurAddress[13] = 0x075b0000; // call ra,($r27),0x2c + CurAddress[14] = 0x8f7e0010; // ldl $r27,16(sp) + CurAddress[15] = 0x8dfe0008; // ldl fp,8(sp) + CurAddress[16] = 0x8f5e0000; // ldl ra,0(sp) + CurAddress[17] = 0xfbde0018; // ldi sp,24(sp) + CurAddress[18] = 0xfb7b004c; // ldi $r27,76($r27) + uint32_t CreateStackSpace = 0xfbdeffe8; + + std::atomic_store_explicit( + reinterpret_cast *>(FirstAddress), + CreateStackSpace, std::memory_order_release); + } else { + std::atomic_store_explicit( + reinterpret_cast *>(FirstAddress), + uint32_t(PatchOpcodes::PO_BR), std::memory_order_release); + } + __clear_cache(reinterpret_cast(FirstAddress), + reinterpret_cast(CurAddress)); + return true; +} + +bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled, + void (*Trampoline)()) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampoline); +} + +bool patchFunctionExit(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); +} + +bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); +} + +bool patchCustomEvent(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + // FIXME + return false; +} + +bool patchTypedEvent(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + // FIXME + return false; +} + +} // namespace __xray + +extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { + // FIXME: this will have to be implemented in the trampoline assembly file +} diff --git a/compiler-rt/lib/xray/xray_trampoline_sw64.S b/compiler-rt/lib/xray/xray_trampoline_sw64.S new file mode 100644 index 000000000000..bcfd00c60a15 --- /dev/null +++ b/compiler-rt/lib/xray/xray_trampoline_sw64.S @@ -0,0 +1,99 @@ +#include "../builtins/assembly.h" + .text + .file "xray_trampoline_sw64.S" + .global _ZN6__xray19XRayPatchedFunctionE + .p2align 3 + .global __xray_FunctionEntry + .type __xray_FunctionEntry,@function + .ent __xray_FunctionEntry +__xray_FunctionEntry: + ldih $29,0($27) !gpdisp!1 + ldi $29,0($29) !gpdisp!1 + ldi $30,-112($30) + stl $26, 104($30) + stl $29, 96($30) + stl $21, 88($30) + stl $20, 80($30) + stl $19, 72($30) + stl $18, 64($30) + stl $17, 56($30) + stl $16, 48($30) + fstd $f21, 40($30) + fstd $f20, 32($30) + fstd $f19, 24($30) + fstd $f18, 16($30) + fstd $f17, 8($30) + fstd $f16, 0($30) + ldl $27, _ZN6__xray19XRayPatchedFunctionE($29) !literal!2 + ldl $27, 0($27) + beq $27, FunctionEntry_restore + call $26, ($27),_ZN6__xray19XRayPatchedFunctionE !lituse_jsr!2 +FunctionEntry_restore: + fldd $f16, 0($30) + fldd $f17, 8($30) + fldd $f18, 16($30) + fldd $f19, 24($30) + fldd $f20, 32($30) + fldd $f21, 40($30) + ldl $16, 48($30) + ldl $17, 56($30) + ldl $18, 64($30) + ldl $19, 72($30) + ldl $20, 80($30) + ldl $21, 88($30) + ldl $29, 96($30) + ldl $26, 104($30) + addl $30, 112, $30 + ret $31,($26),1 + .end __xray_FunctionEntry +.Lfunc_end0: + .size __xray_FunctionEntry, .Lfunc_end0-__xray_FunctionEntry + +FunctionEntry_end: + .size __xray_FunctionEntry, FunctionEntry_end-__xray_FunctionEntry + + .p2align 3 + .global __xray_FunctionExit + .type __xray_FunctionExit,@function +__xray_FunctionExit: + ldih $29,0($27) !gpdisp!3 + ldi $29,0($29) !gpdisp!3 + ldi $30,-112($30) + stl $26, 104($30) + stl $29, 96($30) + stl $21, 88($30) + stl $20, 80($30) + stl $19, 72($30) + stl $18, 64($30) + stl $17, 56($30) + stl $16, 48($30) + fstd $f21, 40($30) + fstd $f20, 32($30) + fstd $f19, 24($30) + fstd $f18, 16($30) + fstd $f17, 8($30) + fstd $f16, 0($30) + ldl $27, _ZN6__xray19XRayPatchedFunctionE($29) !literal!4 + ldl $27, 0($27) + beq $27, FunctionExit_restore + call $26, ($27),_ZN6__xray19XRayPatchedFunctionE !lituse_jsr!4 +FunctionExit_restore: + fldd $f16, 0($30) + fldd $f17, 8($30) + fldd $f18, 16($30) + fldd $f19, 24($30) + fldd $f20, 32($30) + fldd $f21, 40($30) + ldl $16, 48($30) + ldl $17, 56($30) + ldl $18, 64($30) + ldl $19, 72($30) + ldl $20, 80($30) + ldl $21, 88($30) + ldl $29, 96($30) + ldl $26, 104($30) + addl $30, 112, $30 + ret $31,($26),1 + .end __xray_FunctionExit +.Lfunc_end1: + .size __xray_FunctionExit, .Lfunc_end1-__xray_FunctionExit diff --git a/compiler-rt/lib/xray/xray_tsc.h b/compiler-rt/lib/xray/xray_tsc.h index e1cafe1bf11d..7555f5d7b5c3 100644 --- a/compiler-rt/lib/xray/xray_tsc.h +++ b/compiler-rt/lib/xray/xray_tsc.h @@ -43,7 +43,7 @@ inline uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT { #elif defined(__powerpc64__) #include "xray_powerpc64.inc" #elif defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ - defined(__hexagon__) || defined(__loongarch_lp64) + defined(__hexagon__) || defined(__loongarch_lp64) || defined(__sw_64__) // Emulated TSC. // There is no instruction like RDTSCP in user mode on ARM. ARM's CP15 does // not have a constant frequency like TSC on x86(_64), it may go faster diff --git a/compiler-rt/test/asan/CMakeLists.txt b/compiler-rt/test/asan/CMakeLists.txt index 70c282a621c3..c62e8d230ddb 100644 --- a/compiler-rt/test/asan/CMakeLists.txt +++ b/compiler-rt/test/asan/CMakeLists.txt @@ -14,7 +14,7 @@ if(OS_NAME MATCHES "Windows" AND CMAKE_SIZEOF_VOID_P EQUAL 8 AND endif() macro(get_bits_for_arch arch bits) - if (${arch} MATCHES "x86_64|powerpc64|powerpc64le|aarch64|arm64|mips64|mips64el|s390x|sparcv9|riscv64|loongarch64") + if (${arch} MATCHES "x86_64|powerpc64|powerpc64le|aarch64|arm64|mips64|mips64el|s390x|sparcv9|riscv64|loongarch64|sw_64") set(${bits} 64) elseif (${arch} MATCHES "i386|arm|mips|mipsel|sparc") set(${bits} 32) diff --git a/compiler-rt/test/asan/TestCases/Linux/ptrace.cpp b/compiler-rt/test/asan/TestCases/Linux/ptrace.cpp index e01021ff344c..013707be958a 100644 --- a/compiler-rt/test/asan/TestCases/Linux/ptrace.cpp +++ b/compiler-rt/test/asan/TestCases/Linux/ptrace.cpp @@ -1,6 +1,7 @@ // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 // XFAIL: android // XFAIL: target=mips{{.*}} +// XFAIL: sw_64 // // RUN: %clangxx_asan -O0 %s -o %t && %run %t // RUN: %clangxx_asan -DPOSITIVE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s @@ -58,6 +59,15 @@ typedef elf_fpregset_t fpregs_struct; #define PRINT_REG_FP(__fpregs) printf ("%lx\n", (elf_greg_t) (__fpregs[32])) #define __PTRACE_FPREQUEST PTRACE_GETFPREGS +#elif defined(__sw_64__) +# include +# include +typedef struct pt_regs regs_struct; +typedef fpregset_t fpregs_struct; +#define PRINT_REG_PC(__regs) printf ("%lx\n", (unsigned long) (__regs.pc)) +#define PRINT_REG_FP(__fpregs) printf ("%lx\n", (elf_greg_t) (__fpregs[32])) +#define __PTRACE_FPREQUEST PTRACE_GETFPREGS + #elif defined(__arm__) # include # include diff --git a/compiler-rt/test/fuzzer/fork-ubsan.test b/compiler-rt/test/fuzzer/fork-ubsan.test index 2d68b72fe6bb..8740132f251b 100644 --- a/compiler-rt/test/fuzzer/fork-ubsan.test +++ b/compiler-rt/test/fuzzer/fork-ubsan.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: darwin, target={{.*freebsd.*}}, target=aarch64{{.*}} +# UNSUPPORTED: darwin, target={{.*freebsd.*}}, target=aarch64{{.*}}, target=sw_64{{.*}} # Tests how the fork mode works together with ubsan. RUN: %cpp_compiler %S/IntegerOverflowTest.cpp -o %t-IntegerOverflowTest -fsanitize=signed-integer-overflow -fno-sanitize-recover=signed-integer-overflow RUN: not %run %t-IntegerOverflowTest -fork=1 -ignore_crashes=1 -runs=10000 2>&1 | FileCheck %s --check-prefix=UBSAN_FORK diff --git a/compiler-rt/test/lit.common.cfg.py b/compiler-rt/test/lit.common.cfg.py index e95f430f1961..09308cd5d9ce 100644 --- a/compiler-rt/test/lit.common.cfg.py +++ b/compiler-rt/test/lit.common.cfg.py @@ -859,7 +859,7 @@ elif config.android: # Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL # because the test hangs or fails on one configuration and not the other. -if config.android or (config.target_arch not in ["arm", "armhf", "aarch64"]): +if config.android or (config.target_arch not in ['arm', 'armhf', 'aarch64', 'sw_64']): config.available_features.add("stable-runtime") if config.asan_shadow_scale: @@ -882,6 +882,10 @@ run_wrapper = [] target_cflags = [getattr(config, "target_cflags", None)] extra_cflags = [] +# On Sw64 we need -mlong-double=64 to make some test pass. +if config.target_arch == 'sw_64': + extra_cflags += ["-mlong-double-64"] + if config.use_lto and config.lto_supported: extra_cflags += config.lto_flags elif config.use_lto and (not config.lto_supported): diff --git a/compiler-rt/test/lsan/TestCases/use_registers.cpp b/compiler-rt/test/lsan/TestCases/use_registers.cpp index a4fbf27aefb6..fe58bc1a8fc5 100644 --- a/compiler-rt/test/lsan/TestCases/use_registers.cpp +++ b/compiler-rt/test/lsan/TestCases/use_registers.cpp @@ -57,6 +57,8 @@ extern "C" void *registers_thread_func(void *arg) { asm("mv s11, %0" : : "r"(p)); +#elif defined(__sw_64__) + asm("bis $31,%0,$28" : : "r"(p)); #else #error "Test is not supported on this architecture." #endif diff --git a/compiler-rt/test/lsan/lit.common.cfg.py b/compiler-rt/test/lsan/lit.common.cfg.py index e9b974955730..6e94507ad237 100644 --- a/compiler-rt/test/lsan/lit.common.cfg.py +++ b/compiler-rt/test/lsan/lit.common.cfg.py @@ -115,6 +115,7 @@ supported_linux = ( "armv7l", "s390x", "loongarch64", + "sw_64", ] ) supported_darwin = config.host_os == "Darwin" and config.target_arch in ["x86_64"] diff --git a/compiler-rt/test/sanitizer_common/print_address.h b/compiler-rt/test/sanitizer_common/print_address.h index df31322246a0..e471fd99b242 100644 --- a/compiler-rt/test/sanitizer_common/print_address.h +++ b/compiler-rt/test/sanitizer_common/print_address.h @@ -12,7 +12,7 @@ void print_address(const char *str, int n, ...) { void *p = va_arg(ap, void *); #if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) || \ defined(__s390x__) || (defined(__riscv) && __riscv_xlen == 64) || \ - defined(__loongarch_lp64) + defined(__loongarch_lp64) || defined(__sw_64__) // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not // match to the format used in the diagnotic message. fprintf(stderr, "0x%012lx ", (unsigned long) p); @@ -25,4 +25,4 @@ void print_address(const char *str, int n, ...) { fprintf(stderr, "\n"); } -#endif // __SANITIZER_COMMON_PRINT_ADDRESS_H__ \ No newline at end of file +#endif // __SANITIZER_COMMON_PRINT_ADDRESS_H__ diff --git a/compiler-rt/test/tsan/map32bit.cpp b/compiler-rt/test/tsan/map32bit.cpp index e8bac22647bb..c2d8d244a380 100644 --- a/compiler-rt/test/tsan/map32bit.cpp +++ b/compiler-rt/test/tsan/map32bit.cpp @@ -13,6 +13,7 @@ // XFAIL: target=powerpc64{{.*}} // XFAIL: target=s390x{{.*}} // XFAIL: target=loongarch64{{.*}} +// XFAIL: target=sw_64{{.*}} // MAP_32BIT doesn't exist on OS X and NetBSD. // UNSUPPORTED: darwin,target={{.*netbsd.*}} diff --git a/compiler-rt/test/tsan/mmap_large.cpp b/compiler-rt/test/tsan/mmap_large.cpp index 85ebe7f76b02..91a80650cee3 100644 --- a/compiler-rt/test/tsan/mmap_large.cpp +++ b/compiler-rt/test/tsan/mmap_large.cpp @@ -19,7 +19,7 @@ int main() { const size_t kLog2Size = 39; #elif defined(__mips64) || defined(__aarch64__) || defined(__loongarch_lp64) const size_t kLog2Size = 32; -#elif defined(__powerpc64__) +#elif defined(__powerpc64__) || defined(__sw_64__) const size_t kLog2Size = 39; #elif defined(__s390x__) const size_t kLog2Size = 43; diff --git a/llvm/lib/Target/Sw64/Sw64AsmPrinter.cpp b/llvm/lib/Target/Sw64/Sw64AsmPrinter.cpp index 36168e986db4..c5e48099eed9 100644 --- a/llvm/lib/Target/Sw64/Sw64AsmPrinter.cpp +++ b/llvm/lib/Target/Sw64/Sw64AsmPrinter.cpp @@ -39,6 +39,7 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/MC/TargetRegistry.h" @@ -87,6 +88,17 @@ public: bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const { return LowerSw64MachineOperandToMCOperand(MO, MCOp, *this); } + //===------------------------------------------------------------------===// + // XRay implementation + //===------------------------------------------------------------------===// +public: + // XRay-specific lowering for Sw64. + void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI); + void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI); + void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI); + +private: + void emitSled(const MachineInstr &MI, SledKind Kind); }; } // end of anonymous namespace @@ -94,6 +106,7 @@ bool Sw64AsmPrinter::runOnMachineFunction(MachineFunction &MF) { // Initialize TargetLoweringObjectFile. AsmPrinter::runOnMachineFunction(MF); + emitXRayTable(); return true; } diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index f4bf6db569f2..51565c82aa4a 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -117,6 +117,7 @@ static const uint64_t kNetBSD_ShadowOffset64 = 1ULL << 46; static const uint64_t kNetBSDKasan_ShadowOffset64 = 0xdfff900000000000; static const uint64_t kPS_ShadowOffset64 = 1ULL << 40; static const uint64_t kWindowsShadowOffset32 = 3ULL << 28; +static const uint64_t kSW64_ShadowOffset64 = 1ULL << 49; static const uint64_t kEmscriptenShadowOffset = 0; // The shadow memory space is dynamically allocated. @@ -498,6 +499,7 @@ static ShadowMapping getShadowMapping(const Triple &TargetTriple, int LongSize, bool IsFuchsia = TargetTriple.isOSFuchsia(); bool IsEmscripten = TargetTriple.isOSEmscripten(); bool IsAMDGPU = TargetTriple.isAMDGPU(); + bool IsSW64 = TargetTriple.isSw64(); ShadowMapping Mapping; @@ -571,6 +573,8 @@ static ShadowMapping getShadowMapping(const Triple &TargetTriple, int LongSize, else if (IsAMDGPU) Mapping.Offset = (kSmallX86_64ShadowOffsetBase & (kSmallX86_64ShadowOffsetAlignMask << Mapping.Scale)); + else if (IsSW64) + Mapping.Offset = kSW64_ShadowOffset64; else Mapping.Offset = kDefaultShadowOffset64; } diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp index 362fd6e4151f..f656a21b58e9 100644 --- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -447,6 +447,14 @@ static const MemoryMapParams Linux_LoongArch64_MemoryMapParams = { 0x100000000000, // OriginBase }; +// sw_64 Linux +static const MemoryMapParams Linux_SW64_MemoryMapParams = { + 0, // AndMask (not used) + 0x1000000000000ULL, // XorMask + 0, // ShadowBase (not used) + 0x4000000000000ULL, // OriginBase +}; + // aarch64 FreeBSD static const MemoryMapParams FreeBSD_AArch64_MemoryMapParams = { 0x1800000000000, // AndMask @@ -509,6 +517,11 @@ static const PlatformMemoryMapParams Linux_LoongArch_MemoryMapParams = { &Linux_LoongArch64_MemoryMapParams, }; +static const PlatformMemoryMapParams Linux_Sw64_MemoryMapParams = { + nullptr, + &Linux_SW64_MemoryMapParams, +}; + static const PlatformMemoryMapParams FreeBSD_ARM_MemoryMapParams = { nullptr, &FreeBSD_AArch64_MemoryMapParams, @@ -555,6 +568,7 @@ private: friend struct VarArgAArch64Helper; friend struct VarArgPowerPC64Helper; friend struct VarArgSystemZHelper; + friend struct VarArgSw64Helper; void initializeModule(Module &M); void initializeCallbacks(Module &M, const TargetLibraryInfo &TLI); @@ -1033,6 +1047,9 @@ void MemorySanitizer::initializeModule(Module &M) { case Triple::loongarch64: MapParams = Linux_LoongArch_MemoryMapParams.bits64; break; + case Triple::sw_64: + MapParams = Linux_Sw64_MemoryMapParams.bits64; + break; default: report_fatal_error("unsupported architecture"); } @@ -5332,6 +5349,170 @@ struct VarArgAArch64Helper : public VarArgHelper { } }; +/// Sw64-specific implementation of VarArgHelper. +struct VarArgSw64Helper : public VarArgHelper { + static const unsigned kSw64GrArgSize = 64; + static const unsigned kSw64VrArgSize = 64; + static const unsigned Sw64GrBegOffset = 0; + static const unsigned Sw64GrEndOffset = kSw64GrArgSize; + // Make VR space aligned to 16 bytes. + static const unsigned Sw64VrBegOffset = Sw64GrEndOffset; + static const unsigned Sw64VrEndOffset = Sw64VrBegOffset + kSw64VrArgSize; + static const unsigned Sw64VAEndOffset = Sw64VrEndOffset; + + Function &F; + MemorySanitizer &MS; + MemorySanitizerVisitor &MSV; + Value *VAArgTLSCopy = nullptr; + Value *VAArgOverflowSize = nullptr; + + SmallVector VAStartInstrumentationList; + + enum ArgKind { AK_GeneralPurpose, AK_FloatingPoint, AK_Memory }; + + VarArgSw64Helper(Function &F, MemorySanitizer &MS, + MemorySanitizerVisitor &MSV) + : F(F), MS(MS), MSV(MSV) {} + + ArgKind classifyArgument(Value *arg) { + Type *T = arg->getType(); + if (T->isFPOrFPVectorTy()) + return AK_FloatingPoint; + if ((T->isIntegerTy() && T->getPrimitiveSizeInBits() <= 64) || + (T->isPointerTy())) + return AK_GeneralPurpose; + return AK_Memory; + } + + // The instrumentation stores the argument shadow in a non ABI-specific + // format because it does not know which argument is named. + // The first seven GR registers are saved in the first 56 bytes of the + // va_arg tls arra, followers by the first 8 FP/SIMD registers, and then + // the remaining arguments. + // Using constant offset within the va_arg TLS array allows fast copy + // in the finalize instrumentation. + void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override { + unsigned VAArgOffset = 0; + const DataLayout &DL = F.getParent()->getDataLayout(); + for (auto ArgIt = CB.arg_begin() + CB.getFunctionType()->getNumParams(), + End = CB.arg_end(); + ArgIt != End; ++ArgIt) { + Triple TargetTriple(F.getParent()->getTargetTriple()); + Value *A = *ArgIt; + Value *Base; + uint64_t ArgSize = DL.getTypeAllocSize(A->getType()); + if (TargetTriple.getArch() == Triple::mips64) { + // Adjusting the shadow for argument with size < 8 to match the + // placement of bits in big endian system + if (ArgSize < 8) + VAArgOffset += (8 - ArgSize); + } + Base = getShadowPtrForVAArgument(A->getType(), IRB, VAArgOffset, ArgSize); + VAArgOffset += ArgSize; + VAArgOffset = alignTo(VAArgOffset, 8); + if (!Base) + continue; + IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment); + } + + Constant *TotalVAArgSize = ConstantInt::get(IRB.getInt64Ty(), VAArgOffset); + // Here using VAArgOverflowSizeTLS as VAArgSizeTLS to avoid creation of + // a new class member i.e. it is the total size of all VarArgs. + IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS); + } + + /// Compute the shadow address for a given va_arg. + Value *getShadowPtrForVAArgument(Type *Ty, IRBuilder<> &IRB, + unsigned ArgOffset, unsigned ArgSize) { + // Make sure we don't overflow __msan_va_arg_tls. + if (ArgOffset + ArgSize > kParamTLSSize) + return nullptr; + Value *Base = IRB.CreatePointerCast(MS.VAArgTLS, MS.IntptrTy); + Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset)); + return IRB.CreateIntToPtr(Base, PointerType::get(MSV.getShadowTy(Ty), 0), + "_msarg"); + } + + void visitVAStartInst(VAStartInst &I) override { + IRBuilder<> IRB(&I); + VAStartInstrumentationList.push_back(&I); + Value *VAListTag = I.getArgOperand(0); + Value *ShadowPtr, *OriginPtr; + const Align Alignment = Align(8); + std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr( + VAListTag, IRB, IRB.getInt8Ty(), Alignment, /*isStore*/ true); + IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()), + /* size */ 16, Alignment, false); + } + + void visitVACopyInst(VACopyInst &I) override { + IRBuilder<> IRB(&I); + VAStartInstrumentationList.push_back(&I); + Value *VAListTag = I.getArgOperand(0); + Value *ShadowPtr, *OriginPtr; + const Align Alignment = Align(8); + std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr( + VAListTag, IRB, IRB.getInt8Ty(), Alignment, /*isStore*/ true); + IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()), + /* size */ 16, Alignment, false); + } + + // Retrieve a va_list field of 'void*' size. + Value *getVAField64(IRBuilder<> &IRB, Value *VAListTag, int offset) { + Value *SaveAreaPtrPtr = IRB.CreateIntToPtr( + IRB.CreateAdd(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy), + ConstantInt::get(MS.IntptrTy, offset)), + Type::getInt64PtrTy(*MS.C)); + return IRB.CreateLoad(Type::getInt64Ty(*MS.C), SaveAreaPtrPtr); + } + + // Retrieve a va_list field of 'int' size. + Value *getVAField32(IRBuilder<> &IRB, Value *VAListTag, int offset) { + Value *SaveAreaPtr = IRB.CreateIntToPtr( + IRB.CreateAdd(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy), + ConstantInt::get(MS.IntptrTy, offset)), + Type::getInt32PtrTy(*MS.C)); + Value *SaveArea32 = IRB.CreateLoad(IRB.getInt32Ty(), SaveAreaPtr); + return IRB.CreateSExt(SaveArea32, MS.IntptrTy); + } + + void finalizeInstrumentation() override { + assert(!VAArgOverflowSize && !VAArgTLSCopy && + "finalizeInstrumentation called twice"); + IRBuilder<> IRB(MSV.FnPrologueEnd); + VAArgOverflowSize = + IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); + Value *CopySize = + IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, 0), VAArgOverflowSize); + + if (!VAStartInstrumentationList.empty()) { + // If there is a va_start in this function, make a backup copy of + // va_arg_tls somewhere in the function entry block. + VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize); + IRB.CreateMemCpy(VAArgTLSCopy, Align(8), MS.VAArgTLS, Align(8), CopySize); + } + + // Instrument va_start, copy va_list shadow from the backup copy of + // the TLS contents. + for (size_t i = 0, n = VAStartInstrumentationList.size(); i < n; i++) { + CallInst *OrigInst = VAStartInstrumentationList[i]; + IRBuilder<> IRB(OrigInst->getNextNode()); + + Value *VAListTag = OrigInst->getArgOperand(0); + + // Read the stack pointer from the va_list. + Value *StackSaveAreaPtr = getVAField64(IRB, VAListTag, 0); + Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr; + const Align Alignment = Align(8); + std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) = + MSV.getShadowOriginPtr(StackSaveAreaPtr, IRB, IRB.getInt8Ty(), + Align(8), /*isStore*/ true); + IRB.CreateMemCpy(StackSaveAreaPtr, Align(8), VAArgTLSCopy, Align(8), + CopySize); + } + } +}; + /// PowerPC64-specific implementation of VarArgHelper. struct VarArgPowerPC64Helper : public VarArgHelper { Function &F; -- Gitee