/*
* Copyright (c) 2021 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <sys/types.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <mach-o/nlist.h>
#include "Symbol.h"
namespace mach_o {
//
// MARK: --- Symbol methods ---
//
Symbol Symbol::makeRegularExport(CString name, uint64_t imageOffset, uint8_t sectNum, bool dontDeadStrip, bool cold, bool neverStrip)
{
Symbol symbol(name);
symbol._kind = Kind::regular;
symbol._sectOrdinal = sectNum;
symbol._scope = neverStrip ? Scope::globalNeverStrip : Scope::global;
symbol._implOffset = imageOffset;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
Symbol Symbol::makeRegularHidden(CString name, uint64_t imageOffset, uint8_t sectNum, bool dontDeadStrip, bool cold)
{
Symbol symbol(name);
symbol._kind = Kind::regular;
symbol._sectOrdinal = sectNum;
symbol._scope = Scope::linkageUnit;
symbol._implOffset = imageOffset;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
Symbol Symbol::makeRegularLocal(CString name, uint64_t imageOffset, uint8_t sectNum, bool dontDeadStrip, bool cold)
{
Symbol symbol(name);
symbol._kind = Kind::regular;
symbol._sectOrdinal = sectNum;
symbol._scope = Scope::translationUnit;
symbol._implOffset = imageOffset;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
Symbol Symbol::makeRegularWasPrivateExtern(CString name, uint64_t imageOffset, uint8_t sectNum, bool dontDeadStrip, bool cold)
{
Symbol symbol(name);
symbol._kind = Kind::regular;
symbol._sectOrdinal = sectNum;
symbol._scope = Scope::wasLinkageUnit;
symbol._implOffset = imageOffset;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
Symbol Symbol::makeWeakDefExport(CString name, uint64_t imageOffset, uint8_t sectOrd, bool dontDeadStrip, bool cold)
{
Symbol symbol(name);
symbol._kind = Kind::regular;
symbol._sectOrdinal = sectOrd;
symbol._scope = Scope::global;
symbol._weakDef = true;
symbol._implOffset = imageOffset;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
Symbol Symbol::makeWeakDefAutoHide(CString name, uint64_t imageOffset, uint8_t sectOrd, bool dontDeadStrip, bool cold)
{
Symbol symbol(name);
symbol._kind = Kind::regular;
symbol._sectOrdinal = sectOrd;
symbol._scope = Scope::autoHide;
symbol._weakDef = true;
symbol._implOffset = imageOffset;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
Symbol Symbol::makeWeakDefHidden(CString name, uint64_t imageOffset, uint8_t sectOrd, bool dontDeadStrip, bool cold)
{
Symbol symbol(name);
symbol._kind = Kind::regular;
symbol._sectOrdinal = sectOrd;
symbol._scope = Scope::linkageUnit;
symbol._weakDef = true;
symbol._implOffset = imageOffset;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
Symbol Symbol::makeWeakDefWasPrivateExtern(CString name, uint64_t imageOffset, uint8_t sectOrd, bool dontDeadStrip, bool cold)
{
Symbol symbol(name);
symbol._kind = Kind::regular;
symbol._sectOrdinal = sectOrd;
symbol._scope = Scope::wasLinkageUnit;
symbol._weakDef = true;
symbol._implOffset = imageOffset;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
Symbol Symbol::makeAltEntry(CString name, uint64_t imageOffset, uint8_t sectOrd, Scope scope, bool dontDeadStrip, bool cold, bool weakDef)
{
Symbol symbol(name);
symbol._kind = Kind::altEntry;
symbol._sectOrdinal = sectOrd;
symbol._scope = scope;
symbol._weakDef = weakDef;
symbol._implOffset = imageOffset;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
Symbol Symbol::makeDynamicResolver(CString name, uint8_t sectNum, uint64_t stubImageOffset, uint64_t funcImageOffset)
{
// FIXME: do we need to support non-exported resolver functions?
Symbol symbol(name);
symbol._kind = Kind::resolver;
symbol._scope = Scope::global;
symbol._sectOrdinal = sectNum;
symbol._implOffset = funcImageOffset;
symbol._u.resolverStubOffset = stubImageOffset;
return symbol;
}
Symbol Symbol::makeThreadLocalExport(CString name, uint64_t imageOffset, uint8_t sectOrd, bool dontDeadStrip, bool cold, bool weakDef)
{
Symbol symbol(name);
symbol._kind = Kind::threadLocal;
symbol._scope = Scope::global;
symbol._sectOrdinal = sectOrd;
symbol._implOffset = imageOffset;
symbol._weakDef = weakDef;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
Symbol Symbol::makeAbsoluteExport(CString name, uint64_t address, bool dontDeadStrip)
{
Symbol symbol(name);
symbol._kind = Kind::absolute;
symbol._scope = Scope::global;
symbol._implOffset = address;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
return symbol;
}
Symbol Symbol::makeAbsoluteLocal(CString name, uint64_t address, bool dontDeadStrip)
{
Symbol symbol(name);
symbol._kind = Kind::absolute;
symbol._scope = Scope::translationUnit;
symbol._implOffset = address;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
return symbol;
}
Symbol Symbol::makeReExport(CString name, int libOrdinal, const char* importName, Symbol::Scope scope)
{
Symbol symbol(name);
symbol._kind = Kind::reExport;
symbol._scope = scope;
symbol._implOffset = libOrdinal;
symbol._u.importName = importName;
return symbol;
}
Symbol Symbol::makeUndefined(CString name, int libOrdinal, bool weakImport)
{
Symbol symbol(name);
symbol._kind = Kind::undefine;
symbol._scope = Scope::global;
symbol._implOffset = libOrdinal;
symbol._weakImport = weakImport;
return symbol;
}
Symbol Symbol::makeTentativeDef(CString name, uint64_t size, uint8_t alignP2, bool dontDeadStrip, bool cold)
{
Symbol symbol(name);
symbol._kind = Kind::tentative;
symbol._scope = Scope::global;
symbol._sectOrdinal = alignP2; // sectOrdinal is not used for tent-def, so stuff alignment there
symbol._implOffset = size;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
Symbol Symbol::makeHiddenTentativeDef(CString name, uint64_t size, uint8_t alignP2, bool dontDeadStrip, bool cold)
{
Symbol symbol(name);
symbol._kind = Kind::tentative;
symbol._scope = Scope::linkageUnit;
symbol._sectOrdinal = alignP2; // sectOrdinal is not used for tent-def, so stuff alignment there
symbol._implOffset = size;
if ( dontDeadStrip )
symbol.setDontDeadStrip();
if ( cold )
symbol.setCold();
return symbol;
}
bool Symbol::operator==(const Symbol& other) const
{
if ( _name != other._name )
return false;
if ( _implOffset != other._implOffset )
return false;
if ( _kind != other._kind )
return false;
if ( _scope != other._scope )
return false;
if ( _weakDef != other._weakDef )
return false;
if ( _kind == Kind::reExport ) {
if ( (_u.importName != nullptr) && (other._u.importName != nullptr) && (strcmp(_u.importName, other._u.importName) != 0) )
return false;
if ( _u.importName != other._u.importName )
return false;
}
else if ( _kind == Kind::resolver ) {
if ( _u.resolverStubOffset != other._u.resolverStubOffset )
return false;
}
return true;
}
uint64_t Symbol::implOffset() const
{
assert((_kind != Kind::reExport) && (_kind != Kind::absolute));
return _implOffset;
}
bool Symbol::isDynamicResolver(uint64_t& resolverStubOffset) const
{
if ( _kind != Kind::resolver )
return false;
resolverStubOffset = _u.resolverStubOffset;
return true;
}
bool Symbol::isReExport(int& libOrdinal, const char*& importName) const
{
if ( _kind != Kind::reExport )
return false;
libOrdinal = (int)_implOffset;
importName = (_u.importName != nullptr) ? _u.importName : _name.c_str();
return true;
}
bool Symbol::isAbsolute(uint64_t& absAddress) const
{
if ( _kind != Kind::absolute )
return false;
absAddress = _implOffset;
return true;
}
bool Symbol::isUndefined() const
{
return _kind == Kind::undefine;
}
bool Symbol::isUndefined(int& libOrdinal, bool& weakImport) const
{
if ( _kind != Kind::undefine )
return false;
libOrdinal = (int)_implOffset;
weakImport = _weakImport;
return true;
}
bool Symbol::isRegular(uint64_t& implOffset) const
{
if ( _kind != Kind::regular )
return false;
implOffset = _implOffset;
return true;
}
bool Symbol::isThreadLocal(uint64_t& implOffset) const
{
if ( _kind != Kind::threadLocal )
return false;
implOffset = _implOffset;
return true;
}
bool Symbol::isAltEntry(uint64_t& implOffset) const
{
if ( _kind != Kind::altEntry )
return false;
implOffset = _implOffset;
return true;
}
bool Symbol::isTentativeDef() const
{
return _kind == Kind::tentative;
}
bool Symbol::isTentativeDef(uint64_t& size, uint8_t& p2align) const
{
if ( _kind != Kind::tentative )
return false;
size =_implOffset;
p2align = _sectOrdinal; // sectOrdinal not used by tent-def, so alignment was stored there
return true;
}
void Symbol::setName(const char* newName)
{
_name = newName;
}
void Symbol::setimplOffset(uint64_t newOffset)
{
_implOffset = newOffset;
}
} // namespace mach_o