| //===- lib/MC/MCSymbolELF.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 "llvm/MC/MCSymbolELF.h" |
| #include "llvm/BinaryFormat/ELF.h" |
| |
| namespace llvm { |
| |
| namespace { |
| enum { |
| // Shift value for STT_* flags. 7 possible values. 3 bits. |
| ELF_STT_Shift = 0, |
| |
| // Shift value for STB_* flags. 4 possible values, 2 bits. |
| ELF_STB_Shift = 3, |
| |
| // Shift value for STV_* flags. 4 possible values, 2 bits. |
| ELF_STV_Shift = 5, |
| |
| // Shift value for STO_* flags. 3 bits. All the values are between 0x20 and |
| // 0xe0, so we shift right by 5 before storing. |
| ELF_STO_Shift = 7, |
| |
| // One bit. |
| ELF_IsSignature_Shift = 10, |
| |
| // One bit. |
| ELF_WeakrefUsedInReloc_Shift = 11, |
| |
| // One bit. |
| ELF_BindingSet_Shift = 12, |
| |
| // One bit. |
| ELF_IsMemoryTagged_Shift = 13, |
| }; |
| } |
| |
| void MCSymbolELF::setBinding(unsigned Binding) const { |
| setIsBindingSet(); |
| unsigned Val; |
| switch (Binding) { |
| default: |
| llvm_unreachable("Unsupported Binding"); |
| case ELF::STB_LOCAL: |
| Val = 0; |
| break; |
| case ELF::STB_GLOBAL: |
| Val = 1; |
| break; |
| case ELF::STB_WEAK: |
| Val = 2; |
| break; |
| case ELF::STB_GNU_UNIQUE: |
| Val = 3; |
| break; |
| } |
| uint32_t OtherFlags = getFlags() & ~(0x3 << ELF_STB_Shift); |
| setFlags(OtherFlags | (Val << ELF_STB_Shift)); |
| } |
| |
| unsigned MCSymbolELF::getBinding() const { |
| if (isBindingSet()) { |
| uint32_t Val = (Flags >> ELF_STB_Shift) & 3; |
| switch (Val) { |
| default: |
| llvm_unreachable("Invalid value"); |
| case 0: |
| return ELF::STB_LOCAL; |
| case 1: |
| return ELF::STB_GLOBAL; |
| case 2: |
| return ELF::STB_WEAK; |
| case 3: |
| return ELF::STB_GNU_UNIQUE; |
| } |
| } |
| |
| if (isDefined()) |
| return ELF::STB_LOCAL; |
| if (isUsedInReloc()) |
| return ELF::STB_GLOBAL; |
| if (isWeakrefUsedInReloc()) |
| return ELF::STB_WEAK; |
| if (isSignature()) |
| return ELF::STB_LOCAL; |
| return ELF::STB_GLOBAL; |
| } |
| |
| void MCSymbolELF::setType(unsigned Type) const { |
| unsigned Val; |
| switch (Type) { |
| default: |
| llvm_unreachable("Unsupported Binding"); |
| case ELF::STT_NOTYPE: |
| Val = 0; |
| break; |
| case ELF::STT_OBJECT: |
| Val = 1; |
| break; |
| case ELF::STT_FUNC: |
| Val = 2; |
| break; |
| case ELF::STT_SECTION: |
| Val = 3; |
| break; |
| case ELF::STT_COMMON: |
| Val = 4; |
| break; |
| case ELF::STT_TLS: |
| Val = 5; |
| break; |
| case ELF::STT_GNU_IFUNC: |
| Val = 6; |
| break; |
| } |
| uint32_t OtherFlags = getFlags() & ~(0x7 << ELF_STT_Shift); |
| setFlags(OtherFlags | (Val << ELF_STT_Shift)); |
| } |
| |
| unsigned MCSymbolELF::getType() const { |
| uint32_t Val = (Flags >> ELF_STT_Shift) & 7; |
| switch (Val) { |
| default: |
| llvm_unreachable("Invalid value"); |
| case 0: |
| return ELF::STT_NOTYPE; |
| case 1: |
| return ELF::STT_OBJECT; |
| case 2: |
| return ELF::STT_FUNC; |
| case 3: |
| return ELF::STT_SECTION; |
| case 4: |
| return ELF::STT_COMMON; |
| case 5: |
| return ELF::STT_TLS; |
| case 6: |
| return ELF::STT_GNU_IFUNC; |
| } |
| } |
| |
| void MCSymbolELF::setVisibility(unsigned Visibility) { |
| assert(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_INTERNAL || |
| Visibility == ELF::STV_HIDDEN || Visibility == ELF::STV_PROTECTED); |
| |
| uint32_t OtherFlags = getFlags() & ~(0x3 << ELF_STV_Shift); |
| setFlags(OtherFlags | (Visibility << ELF_STV_Shift)); |
| } |
| |
| unsigned MCSymbolELF::getVisibility() const { |
| unsigned Visibility = (Flags >> ELF_STV_Shift) & 3; |
| return Visibility; |
| } |
| |
| void MCSymbolELF::setOther(unsigned Other) { |
| assert((Other & 0x1f) == 0); |
| Other >>= 5; |
| assert(Other <= 0x7); |
| uint32_t OtherFlags = getFlags() & ~(0x7 << ELF_STO_Shift); |
| setFlags(OtherFlags | (Other << ELF_STO_Shift)); |
| } |
| |
| unsigned MCSymbolELF::getOther() const { |
| unsigned Other = (Flags >> ELF_STO_Shift) & 7; |
| return Other << 5; |
| } |
| |
| void MCSymbolELF::setIsWeakrefUsedInReloc() const { |
| uint32_t OtherFlags = getFlags() & ~(0x1 << ELF_WeakrefUsedInReloc_Shift); |
| setFlags(OtherFlags | (1 << ELF_WeakrefUsedInReloc_Shift)); |
| } |
| |
| bool MCSymbolELF::isWeakrefUsedInReloc() const { |
| return getFlags() & (0x1 << ELF_WeakrefUsedInReloc_Shift); |
| } |
| |
| void MCSymbolELF::setIsSignature() const { |
| uint32_t OtherFlags = getFlags() & ~(0x1 << ELF_IsSignature_Shift); |
| setFlags(OtherFlags | (1 << ELF_IsSignature_Shift)); |
| } |
| |
| bool MCSymbolELF::isSignature() const { |
| return getFlags() & (0x1 << ELF_IsSignature_Shift); |
| } |
| |
| void MCSymbolELF::setIsBindingSet() const { |
| uint32_t OtherFlags = getFlags() & ~(0x1 << ELF_BindingSet_Shift); |
| setFlags(OtherFlags | (1 << ELF_BindingSet_Shift)); |
| } |
| |
| bool MCSymbolELF::isBindingSet() const { |
| return getFlags() & (0x1 << ELF_BindingSet_Shift); |
| } |
| |
| bool MCSymbolELF::isMemtag() const { |
| return getFlags() & (0x1 << ELF_IsMemoryTagged_Shift); |
| } |
| |
| void MCSymbolELF::setMemtag(bool Tagged) { |
| uint32_t OtherFlags = getFlags() & ~(1 << ELF_IsMemoryTagged_Shift); |
| if (Tagged) |
| setFlags(OtherFlags | (1 << ELF_IsMemoryTagged_Shift)); |
| else |
| setFlags(OtherFlags); |
| } |
| } |