[llvm] 016c2f5 - [lld-macho] Support -dyld_env

Vy Nguyen via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 20 07:17:25 PDT 2022


Author: Vy Nguyen
Date: 2022-09-20T10:16:45-04:00
New Revision: 016c2f5e3233e67f48c2a511962101876ef0b94c

URL: https://github.com/llvm/llvm-project/commit/016c2f5e3233e67f48c2a511962101876ef0b94c
DIFF: https://github.com/llvm/llvm-project/commit/016c2f5e3233e67f48c2a511962101876ef0b94c.diff

LOG: [lld-macho] Support -dyld_env

This arg is undocumented but from looking at the code + experiment, it's used to add additional DYLD_ENVIRONMENT load commands to the output.

Differential Revision: https://reviews.llvm.org/D134058

Added: 
    lld/test/MachO/dyld-env.s

Modified: 
    lld/MachO/Config.h
    lld/MachO/Driver.cpp
    lld/MachO/Options.td
    lld/MachO/Writer.cpp
    llvm/include/llvm/BinaryFormat/MachO.h

Removed: 
    


################################################################################
diff  --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index c6e8b2582bd7d..620206f307d6f 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -206,6 +206,8 @@ struct Configuration {
 
   llvm::StringRef osoPrefix;
 
+  std::vector<llvm::StringRef> dyldEnvs;
+
   llvm::MachO::Architecture arch() const { return platformInfo.target.Arch; }
 
   llvm::MachO::PlatformType platform() const {

diff  --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 6bec1086f915d..f13649a911d92 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -1437,6 +1437,17 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
     addFile(arg->getValue(), LoadType::CommandLine, /*isLazy=*/false,
             /*isExplicit=*/false, /*isBundleLoader=*/true);
   }
+  for (auto *arg : args.filtered(OPT_dyld_env)) {
+    StringRef envPair(arg->getValue());
+    if (!envPair.contains('='))
+      error("-dyld_env's argument is  malformed. Expected "
+            "-dyld_env <ENV_VAR>=<VALUE>, got `" +
+            envPair + "`");
+    config->dyldEnvs.push_back(envPair);
+  }
+  if (!config->dyldEnvs.empty() && config->outputType != MH_EXECUTE)
+    error("-dyld_env can only be used when creating executable output");
+
   if (const Arg *arg = args.getLastArg(OPT_umbrella)) {
     if (config->outputType != MH_DYLIB)
       warn("-umbrella used, but not creating dylib");

diff  --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index 6af993a430cb6..e12626c17e29d 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -984,6 +984,10 @@ def objc_stubs_fast : Flag<["-"], "objc_stubs_fast">,
 def objc_stubs_small : Flag<["-"], "objc_stubs_small">,
     HelpText<"Produce smaller stubs for Objective-C method calls with more jumps.">,
     Group<grp_rare>;
+def dyld_env : Separate<["-"], "dyld_env">,
+    MetaVarName<"<dyld_env_var>">,
+    HelpText<"Specifies a LC_DYLD_ENVIRONMENT variable value pair.">,
+    Group<grp_rare>;
 
 def grp_deprecated : OptionGroup<"deprecated">, HelpText<"DEPRECATED">;
 
@@ -1212,10 +1216,6 @@ def debug_snapshot : Flag<["-"], "debug_snapshot">,
     Group<grp_undocumented>;
 def demangle : Flag<["-"], "demangle">,
     HelpText<"Demangle symbol names in diagnostics">;
-def dyld_env : Flag<["-"], "dyld_env">,
-    HelpText<"This option is undocumented in ld64">,
-    Flags<[HelpHidden]>,
-    Group<grp_undocumented>;
 def encryptable : Flag<["-"], "encryptable">,
     HelpText<"Generate the LC_ENCRYPTION_INFO load command">,
     Group<grp_undocumented>;

diff  --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index a8ae554a6246f..d0207bbf500e3 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -408,6 +408,31 @@ class LCRPath final : public LoadCommand {
   StringRef path;
 };
 
+class LCDyldEnv final : public LoadCommand {
+public:
+  explicit LCDyldEnv(StringRef name) : name(name) {}
+
+  uint32_t getSize() const override {
+    return alignTo(sizeof(dyld_env_command) + name.size() + 1,
+                   target->wordSize);
+  }
+
+  void writeTo(uint8_t *buf) const override {
+    auto *c = reinterpret_cast<dyld_env_command *>(buf);
+    buf += sizeof(dyld_env_command);
+
+    c->cmd = LC_DYLD_ENVIRONMENT;
+    c->cmdsize = getSize();
+    c->name = sizeof(dyld_env_command);
+
+    memcpy(buf, name.data(), name.size());
+    buf[name.size()] = '\0';
+  }
+
+private:
+  StringRef name;
+};
+
 class LCMinVersion final : public LoadCommand {
 public:
   explicit LCMinVersion(const PlatformInfo &platformInfo)
@@ -822,6 +847,9 @@ template <class LP> void Writer::createLoadCommands() {
           make<LCDylib>(LC_REEXPORT_DYLIB, dylibFile->installName));
   }
 
+  for (const auto &dyldEnv : config->dyldEnvs)
+    in.header->addLoadCommand(make<LCDyldEnv>(dyldEnv));
+
   if (functionStartsSection)
     in.header->addLoadCommand(make<LCFunctionStarts>(functionStartsSection));
   if (dataInCodeSection)

diff  --git a/lld/test/MachO/dyld-env.s b/lld/test/MachO/dyld-env.s
new file mode 100644
index 0000000000000..f86320ce26c35
--- /dev/null
+++ b/lld/test/MachO/dyld-env.s
@@ -0,0 +1,41 @@
+# REQUIRES: x86
+
+# RUN: rm -rf %t && mkdir %t
+
+# RUN: llvm-mc -filetype obj -triple x86_64-apple-darwin %s -o %t/main.o
+
+# RUN: %lld -lSystem -dyld_env DYLD_FRAMEWORK_PATH=./Foo.framework %t/main.o -o %t/one_dyld_env.out
+# RUN: llvm-otool -l %t/one_dyld_env.out | FileCheck %s --check-prefix=ONE-ENV
+
+# RUN: %lld -lSystem -dyld_env DYLD_FRAMEWORK_PATH=./Foo.framework \
+# RUN:               -dyld_env DYLD_FRAMEWORK_PATH=./Bar.framework \
+# RUN:               %t/main.o -o %t/two_dyld_envs.out
+# RUN: llvm-otool -l %t/two_dyld_envs.out | FileCheck %s --check-prefix=TWO-ENV
+
+# RUN: not %lld -lSystem -dyld_env DYLD_FRAMEWORK_PATH,./Foo %t/main.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=MALFORMED
+
+# RUN: not %lld  -dylib -lSystem -dyld_env DYLD_FRAMEWORK_PATH=./Foo %t/main.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=DYLIB
+
+# ONE-ENV:     Load command 11
+# ONE-ENV-NEXT:          cmd LC_DYLD_ENVIRONMENT
+# ONE-ENV-NEXT:      cmdsize 48
+# ONE-ENV-NEXT:         name DYLD_FRAMEWORK_PATH=./Foo.framework (offset 12)
+
+# TWO-ENV:      Load command 11
+# TWO-ENV-NEXT:          cmd LC_DYLD_ENVIRONMENT
+# TWO-ENV-NEXT:      cmdsize 48
+# TWO-ENV-NEXT:         name DYLD_FRAMEWORK_PATH=./Foo.framework (offset 12)
+# TWO-ENV-NEXT: Load command 12
+# TWO-ENV-NEXT:          cmd LC_DYLD_ENVIRONMENT
+# TWO-ENV-NEXT:      cmdsize 48
+# TWO-ENV-NEXT:         name DYLD_FRAMEWORK_PATH=./Bar.framework (offset 12)
+
+# MALFORMED: error: -dyld_env's argument is malformed. Expected -dyld_env <ENV_VAR>=<VALUE>, got `DYLD_FRAMEWORK_PATH,./Foo`
+
+# DYLIB: error: -dyld_env can only be used when creating executable output
+
+.section __TEXT,__text
+
+.global _main
+_main:
+  ret

diff  --git a/llvm/include/llvm/BinaryFormat/MachO.h b/llvm/include/llvm/BinaryFormat/MachO.h
index 4616daf30d448..6205cd82067d4 100644
--- a/llvm/include/llvm/BinaryFormat/MachO.h
+++ b/llvm/include/llvm/BinaryFormat/MachO.h
@@ -869,6 +869,12 @@ struct build_version_command {
   uint32_t ntools;   // number of tool entries following this
 };
 
+struct dyld_env_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t name;
+};
+
 struct dyld_info_command {
   uint32_t cmd;
   uint32_t cmdsize;


        


More information about the llvm-commits mailing list