Index: lld/ELF/Driver.cpp
--- lld/ELF/Driver.cpp.orig
+++ lld/ELF/Driver.cpp
@@ -448,8 +448,19 @@ static void checkOptions() {
   }
 
   if (config->executeOnly) {
-    if (config->emachine != EM_AARCH64)
-      error("--execute-only is only supported on AArch64 targets");
+    switch (config->emachine) {
+    case EM_386:
+    case EM_AARCH64:
+    case EM_MIPS:
+    case EM_PPC:
+    case EM_PPC64:
+    case EM_RISCV:
+    case EM_SPARCV9:
+    case EM_X86_64:
+      break;
+    default:
+      error("-execute-only is not supported on this target");
+    }
 
     if (config->singleRoRx && !script->hasSectionsCommand)
       error("--execute-only and --no-rosegment cannot be used together");
@@ -1290,8 +1301,6 @@ static void readConfigs(opt::InputArgList &args) {
   errorHandler().errorHandlingScript =
       args.getLastArgValue(OPT_error_handling_script);
 
-  config->executeOnly =
-      args.hasFlag(OPT_execute_only, OPT_no_execute_only, false);
   config->exportDynamic =
       args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false) ||
       args.hasArg(OPT_shared);
@@ -1312,8 +1321,15 @@ static void readConfigs(opt::InputArgList &args) {
   config->icf = getICF(args);
   config->ignoreDataAddressEquality =
       args.hasArg(OPT_ignore_data_address_equality);
+#if defined(__OpenBSD__)
+  // Needed to allow preemption of protected symbols (e.g. memcpy) on at least i386.
   config->ignoreFunctionAddressEquality =
+      args.hasFlag(OPT_ignore_function_address_equality,
+                   OPT_no_ignore_function_address_equality, true);
+#else
+  config->ignoreFunctionAddressEquality =
       args.hasArg(OPT_ignore_function_address_equality);
+#endif
   config->init = args.getLastArgValue(OPT_init, "_init");
   config->ltoAAPipeline = args.getLastArgValue(OPT_lto_aa_pipeline);
   config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate);
@@ -1380,7 +1396,12 @@ static void readConfigs(opt::InputArgList &args) {
   config->orphanHandling = getOrphanHandling(args);
   config->outputFile = args.getLastArgValue(OPT_o);
   config->packageMetadata = args.getLastArgValue(OPT_package_metadata);
+#ifdef __OpenBSD__
+  config->pie = args.hasFlag(OPT_pie, OPT_no_pie,
+      !args.hasArg(OPT_shared) && !args.hasArg(OPT_relocatable));
+#else
   config->pie = args.hasFlag(OPT_pie, OPT_no_pie, false);
+#endif
   config->printIcfSections =
       args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
   config->printGcSections =
@@ -1459,7 +1480,7 @@ static void readConfigs(opt::InputArgList &args) {
   config->trace = args.hasArg(OPT_trace);
   config->undefined = args::getStrings(args, OPT_undefined);
   config->undefinedVersion =
-      args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, false);
+      args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true);
   config->unique = args.hasArg(OPT_unique);
   config->useAndroidRelrTags = args.hasFlag(
       OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false);
@@ -1484,6 +1505,7 @@ static void readConfigs(opt::InputArgList &args) {
       args, "keep-text-section-prefix", "nokeep-text-section-prefix", false);
   config->zLrodataAfterBss =
       getZFlag(args, "lrodata-after-bss", "nolrodata-after-bss", false);
+  config->zNoBtCfi = hasZOption(args, "nobtcfi");
   config->zNodefaultlib = hasZOption(args, "nodefaultlib");
   config->zNodelete = hasZOption(args, "nodelete");
   config->zNodlopen = hasZOption(args, "nodlopen");
@@ -1665,9 +1687,9 @@ static void readConfigs(opt::InputArgList &args) {
             arg->getValue() + "'");
     parallel::strategy = hardware_concurrency(threads);
     config->thinLTOJobs = v;
-  } else if (parallel::strategy.compute_thread_count() > 16) {
-    log("set maximum concurrency to 16, specify --threads= to change");
-    parallel::strategy = hardware_concurrency(16);
+  } else if (parallel::strategy.compute_thread_count() > 4) {
+    log("set maximum concurrency to 4, specify --threads= to change");
+    parallel::strategy = hardware_concurrency(4);
   }
   if (auto *arg = args.getLastArg(OPT_thinlto_jobs_eq))
     config->thinLTOJobs = arg->getValue();
@@ -1885,6 +1907,23 @@ static void setConfigs(opt::InputArgList &args) {
       error("cannot open --why-extract= file " + config->whyExtract + ": " +
             e.message());
   }
+
+  config->executeOnly = false;
+#ifdef __OpenBSD__
+  switch (m) {
+  case EM_AARCH64:
+  case EM_MIPS:
+  case EM_PPC:
+  case EM_PPC64:
+  case EM_RISCV:
+  case EM_SPARCV9:
+  case EM_X86_64:
+    config->executeOnly = true;
+    break;
+  }
+#endif
+  config->executeOnly =
+      args.hasFlag(OPT_execute_only, OPT_no_execute_only, config->executeOnly);
 }
 
 static bool isFormatBinary(StringRef s) {
@@ -2050,7 +2089,7 @@ void LinkerDriver::inferMachineType() {
 }
 
 // Parse -z max-page-size=<value>. The default value is defined by
-// each target.
+// each target. Is set to 1 if given nmagic or omagic.
 static uint64_t getMaxPageSize(opt::InputArgList &args) {
   uint64_t val = args::getZOptionValue(args, OPT_z, "max-page-size",
                                        target->defaultMaxPageSize);
@@ -2067,7 +2106,7 @@ static uint64_t getMaxPageSize(opt::InputArgList &args
 }
 
 // Parse -z common-page-size=<value>. The default value is defined by
-// each target.
+// each target. Is set to 1 if given nmagic or omagic.
 static uint64_t getCommonPageSize(opt::InputArgList &args) {
   uint64_t val = args::getZOptionValue(args, OPT_z, "common-page-size",
                                        target->defaultCommonPageSize);
@@ -2086,6 +2125,16 @@ static uint64_t getCommonPageSize(opt::InputArgList &a
   return val;
 }
 
+// Parse -z max-page-size=<value>. The default value is defined by
+// each target.
+static uint64_t getRealMaxPageSize(opt::InputArgList &args) {
+  uint64_t val = args::getZOptionValue(args, OPT_z, "max-page-size",
+                                       target->defaultMaxPageSize);
+  if (!isPowerOf2_64(val))
+    error("max-page-size: value isn't a power of 2");
+  return val;
+}
+
 // Parses --image-base option.
 static std::optional<uint64_t> getImageBase(opt::InputArgList &args) {
   // Because we are using "Config->maxPageSize" here, this function has to be
@@ -3108,6 +3157,11 @@ template <class ELFT> void LinkerDriver::link(opt::Inp
   // optimizations such as DATA_SEGMENT_ALIGN in linker scripts. LLD's use of it
   // is limited to writing trap instructions on the last executable segment.
   config->commonPageSize = getCommonPageSize(args);
+  // textAlignPageSize is the alignment page size to use when aligning PT_LOAD
+  // sections. This is the same as maxPageSize except under -omagic, where data
+  // sections are non-aligned (maxPageSize set to 1) but text sections are aligned
+  // to the target page size.
+  config->textAlignPageSize = config->omagic ? getRealMaxPageSize(args) : config->maxPageSize;
 
   config->imageBase = getImageBase(args);
 
