@@ -535,6 +535,84 @@ static std::string createResponseFile(const opt::InputArgList &Args) {
535535 return Data.str ();
536536}
537537
538+ // The --wrap option is a feature to rename symbols so that you can write
539+ // wrappers for existing functions. If you pass `-wrap=foo`, all
540+ // occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are
541+ // expected to write `wrap_foo` function as a wrapper). The original
542+ // symbol becomes accessible as `real_foo`, so you can call that from your
543+ // wrapper.
544+ //
545+ // This data structure is instantiated for each -wrap option.
546+ struct WrappedSymbol {
547+ Symbol *Sym;
548+ Symbol *Real;
549+ Symbol *Wrap;
550+ };
551+
552+ static Symbol *addUndefined (StringRef Name) {
553+ return Symtab->addUndefinedFunction (Name, " " , " " , 0 , nullptr , nullptr );
554+ }
555+
556+ // Handles -wrap option.
557+ //
558+ // This function instantiates wrapper symbols. At this point, they seem
559+ // like they are not being used at all, so we explicitly set some flags so
560+ // that LTO won't eliminate them.
561+ static std::vector<WrappedSymbol> addWrappedSymbols (opt::InputArgList &Args) {
562+ std::vector<WrappedSymbol> V;
563+ DenseSet<StringRef> Seen;
564+
565+ for (auto *Arg : Args.filtered (OPT_wrap)) {
566+ StringRef Name = Arg->getValue ();
567+ if (!Seen.insert (Name).second )
568+ continue ;
569+
570+ Symbol *Sym = Symtab->find (Name);
571+ if (!Sym)
572+ continue ;
573+
574+ Symbol *Real = addUndefined (Saver.save (" __real_" + Name));
575+ Symbol *Wrap = addUndefined (Saver.save (" __wrap_" + Name));
576+ V.push_back ({Sym, Real, Wrap});
577+
578+ // We want to tell LTO not to inline symbols to be overwritten
579+ // because LTO doesn't know the final symbol contents after renaming.
580+ Real->CanInline = false ;
581+ Sym->CanInline = false ;
582+
583+ // Tell LTO not to eliminate these symbols.
584+ Sym->IsUsedInRegularObj = true ;
585+ Wrap->IsUsedInRegularObj = true ;
586+ Real->IsUsedInRegularObj = false ;
587+ }
588+ return V;
589+ }
590+
591+ // Do renaming for -wrap by updating pointers to symbols.
592+ //
593+ // When this function is executed, only InputFiles and symbol table
594+ // contain pointers to symbol objects. We visit them to replace pointers,
595+ // so that wrapped symbols are swapped as instructed by the command line.
596+ static void wrapSymbols (ArrayRef<WrappedSymbol> Wrapped) {
597+ DenseMap<Symbol *, Symbol *> Map;
598+ for (const WrappedSymbol &W : Wrapped) {
599+ Map[W.Sym ] = W.Wrap ;
600+ Map[W.Real ] = W.Sym ;
601+ }
602+
603+ // Update pointers in input files.
604+ parallelForEach (Symtab->ObjectFiles , [&](InputFile *File) {
605+ MutableArrayRef<Symbol *> Syms = File->getMutableSymbols ();
606+ for (size_t I = 0 , E = Syms.size (); I != E; ++I)
607+ if (Symbol *S = Map.lookup (Syms[I]))
608+ Syms[I] = S;
609+ });
610+
611+ // Update pointers in the symbol table.
612+ for (const WrappedSymbol &W : Wrapped)
613+ Symtab->wrap (W.Sym , W.Real , W.Wrap );
614+ }
615+
538616void LinkerDriver::link (ArrayRef<const char *> ArgsArr) {
539617 WasmOptTable Parser;
540618 opt::InputArgList Args = Parser.parse (ArgsArr.slice (1 ));
@@ -628,6 +706,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
628706 for (auto *Arg : Args.filtered (OPT_export))
629707 handleUndefined (Arg->getValue ());
630708
709+ // Create wrapped symbols for -wrap option.
710+ std::vector<WrappedSymbol> Wrapped = addWrappedSymbols (Args);
711+
631712 // Do link-time optimization if given files are LLVM bitcode files.
632713 // This compiles bitcode files into real object files.
633714 Symtab->addCombinedLTOObject ();
@@ -640,6 +721,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
640721 if (errorCount ())
641722 return ;
642723
724+ // Apply symbol renames for -wrap.
725+ if (!Wrapped.empty ())
726+ wrapSymbols (Wrapped);
727+
643728 for (auto *Arg : Args.filtered (OPT_export)) {
644729 Symbol *Sym = Symtab->find (Arg->getValue ());
645730 if (Sym && Sym->isDefined ())
0 commit comments