forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			134 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- ELFConfig.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 "CopyConfig.h"
 | 
						|
#include "llvm/ADT/Optional.h"
 | 
						|
#include "llvm/ADT/StringSwitch.h"
 | 
						|
#include "llvm/Support/Errc.h"
 | 
						|
#include "llvm/Support/Error.h"
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
namespace objcopy {
 | 
						|
namespace elf {
 | 
						|
 | 
						|
static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue,
 | 
						|
                                                  uint8_t DefaultVisibility) {
 | 
						|
  // Parse value given with --add-symbol option and create the
 | 
						|
  // new symbol if possible. The value format for --add-symbol is:
 | 
						|
  //
 | 
						|
  // <name>=[<section>:]<value>[,<flags>]
 | 
						|
  //
 | 
						|
  // where:
 | 
						|
  // <name> - symbol name, can be empty string
 | 
						|
  // <section> - optional section name. If not given ABS symbol is created
 | 
						|
  // <value> - symbol value, can be decimal or hexadecimal number prefixed
 | 
						|
  //           with 0x.
 | 
						|
  // <flags> - optional flags affecting symbol type, binding or visibility:
 | 
						|
  //           The following are currently supported:
 | 
						|
  //
 | 
						|
  //           global, local, weak, default, hidden, file, section, object,
 | 
						|
  //           indirect-function.
 | 
						|
  //
 | 
						|
  //           The following flags are ignored and provided for GNU
 | 
						|
  //           compatibility only:
 | 
						|
  //
 | 
						|
  //           warning, debug, constructor, indirect, synthetic,
 | 
						|
  //           unique-object, before=<symbol>.
 | 
						|
  NewSymbolInfo SI;
 | 
						|
  StringRef Value;
 | 
						|
  std::tie(SI.SymbolName, Value) = FlagValue.split('=');
 | 
						|
  if (Value.empty())
 | 
						|
    return createStringError(
 | 
						|
        errc::invalid_argument,
 | 
						|
        "bad format for --add-symbol, missing '=' after '%s'",
 | 
						|
        SI.SymbolName.str().c_str());
 | 
						|
 | 
						|
  if (Value.contains(':')) {
 | 
						|
    std::tie(SI.SectionName, Value) = Value.split(':');
 | 
						|
    if (SI.SectionName.empty() || Value.empty())
 | 
						|
      return createStringError(
 | 
						|
          errc::invalid_argument,
 | 
						|
          "bad format for --add-symbol, missing section name or symbol value");
 | 
						|
  }
 | 
						|
 | 
						|
  SmallVector<StringRef, 6> Flags;
 | 
						|
  Value.split(Flags, ',');
 | 
						|
  if (Flags[0].getAsInteger(0, SI.Value))
 | 
						|
    return createStringError(errc::invalid_argument, "bad symbol value: '%s'",
 | 
						|
                             Flags[0].str().c_str());
 | 
						|
 | 
						|
  SI.Visibility = DefaultVisibility;
 | 
						|
 | 
						|
  using Functor = std::function<void(void)>;
 | 
						|
  SmallVector<StringRef, 6> UnsupportedFlags;
 | 
						|
  for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)
 | 
						|
    static_cast<Functor>(
 | 
						|
        StringSwitch<Functor>(Flags[I])
 | 
						|
            .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; })
 | 
						|
            .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; })
 | 
						|
            .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; })
 | 
						|
            .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; })
 | 
						|
            .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; })
 | 
						|
            .CaseLower("protected",
 | 
						|
                       [&SI] { SI.Visibility = ELF::STV_PROTECTED; })
 | 
						|
            .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; })
 | 
						|
            .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; })
 | 
						|
            .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; })
 | 
						|
            .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; })
 | 
						|
            .CaseLower("indirect-function",
 | 
						|
                       [&SI] { SI.Type = ELF::STT_GNU_IFUNC; })
 | 
						|
            .CaseLower("debug", [] {})
 | 
						|
            .CaseLower("constructor", [] {})
 | 
						|
            .CaseLower("warning", [] {})
 | 
						|
            .CaseLower("indirect", [] {})
 | 
						|
            .CaseLower("synthetic", [] {})
 | 
						|
            .CaseLower("unique-object", [] {})
 | 
						|
            .StartsWithLower("before", [] {})
 | 
						|
            .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();
 | 
						|
  if (!UnsupportedFlags.empty())
 | 
						|
    return createStringError(errc::invalid_argument,
 | 
						|
                             "unsupported flag%s for --add-symbol: '%s'",
 | 
						|
                             UnsupportedFlags.size() > 1 ? "s" : "",
 | 
						|
                             join(UnsupportedFlags, "', '").c_str());
 | 
						|
  return SI;
 | 
						|
}
 | 
						|
 | 
						|
Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config) {
 | 
						|
  ELFCopyConfig ELFConfig;
 | 
						|
  if (Config.NewSymbolVisibility) {
 | 
						|
    const uint8_t Invalid = 0xff;
 | 
						|
    ELFConfig.NewSymbolVisibility =
 | 
						|
        StringSwitch<uint8_t>(*Config.NewSymbolVisibility)
 | 
						|
            .Case("default", ELF::STV_DEFAULT)
 | 
						|
            .Case("hidden", ELF::STV_HIDDEN)
 | 
						|
            .Case("internal", ELF::STV_INTERNAL)
 | 
						|
            .Case("protected", ELF::STV_PROTECTED)
 | 
						|
            .Default(Invalid);
 | 
						|
 | 
						|
    if (ELFConfig.NewSymbolVisibility == Invalid)
 | 
						|
      return createStringError(errc::invalid_argument,
 | 
						|
                               "'%s' is not a valid symbol visibility",
 | 
						|
                               Config.NewSymbolVisibility->str().c_str());
 | 
						|
  }
 | 
						|
 | 
						|
  for (StringRef Arg : Config.SymbolsToAdd) {
 | 
						|
    Expected<elf::NewSymbolInfo> NSI = parseNewSymbolInfo(
 | 
						|
        Arg,
 | 
						|
        ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT));
 | 
						|
    if (!NSI)
 | 
						|
      return NSI.takeError();
 | 
						|
    ELFConfig.SymbolsToAdd.push_back(*NSI);
 | 
						|
  }
 | 
						|
 | 
						|
  return ELFConfig;
 | 
						|
}
 | 
						|
 | 
						|
} // end namespace elf
 | 
						|
} // end namespace objcopy
 | 
						|
} // end namespace llvm
 |