[Nasm-devel] [PATCH 1/2] outmacho: Introduce a option for build_version_command
Byoungchan Lee
byoungchan.lee at gmx.com
Sat Jul 17 18:11:00 PDT 2021
From: Byoungchan Lee <daniel.l at hpcnt.com>
The build_version_command is contains the min OS version on which this binary
was built to run for its platform in mach object. It is required for targets
like iOS Catalyst.
Signed-off-by: Byoungchan Lee <daniel.l at hpcnt.com>
---
asm/nasm.c | 24 ++++++++++-
output/macho.h | 15 +++++++
output/outmacho.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 143 insertions(+), 1 deletion(-)
diff --git a/asm/nasm.c b/asm/nasm.c
index 6af92754..0f3b7edc 100644
--- a/asm/nasm.c
+++ b/asm/nasm.c
@@ -167,6 +167,10 @@ static char *quote_for_pmake(const char *str);
static char *quote_for_wmake(const char *str);
static char *(*quote_for_make)(const char *) = quote_for_pmake;
+#if defined(OF_MACHO) || defined(OF_MACHO64)
+extern bool macho_set_min_os(const char *str);
+#endif
+
/*
* Execution limits that can be set via a command-line option or %pragma
*/
@@ -942,7 +946,8 @@ enum text_options {
OPT_KEEP_ALL,
OPT_NO_LINE,
OPT_DEBUG,
- OPT_REPRODUCIBLE
+ OPT_REPRODUCIBLE,
+ OPT_MACHO_MIN_OS
};
enum need_arg {
ARG_NO,
@@ -975,6 +980,7 @@ static const struct textargs textopts[] = {
{"no-line", OPT_NO_LINE, ARG_NO, 0},
{"debug", OPT_DEBUG, ARG_MAYBE, 0},
{"reproducible", OPT_REPRODUCIBLE, ARG_NO, 0},
+ {"macho-min-os", OPT_MACHO_MIN_OS, ARG_YES, 0},
{NULL, OPT_BOGUS, ARG_NO, 0}
};
@@ -1338,6 +1344,20 @@ static bool process_arg(char *p, char *q, int pass)
case OPT_REPRODUCIBLE:
reproducible = true;
break;
+ case OPT_MACHO_MIN_OS:
+ if (pass == 2) {
+ if (strnstr(ofmt->shortname, "macho", 5) != ofmt->shortname) {
+ nasm_error(ERR_WARNING | WARN_OTHER | ERR_USAGE,
+ "macho-min-os is only valid for macho format, current: %s", ofmt->shortname);
+ break;
+ }
+#if defined(OF_MACHO) || defined(OF_MACHO64)
+ if (!macho_set_min_os(param)) {
+ nasm_fatalf(ERR_USAGE, "failed to set minimum os for mach-o '%s'", param);
+ }
+#endif
+ }
+ break;
case OPT_HELP:
help(stdout);
exit(0);
@@ -2297,6 +2317,8 @@ static void help(FILE *out)
"\n"
" --reproducible attempt to produce run-to-run identical output\n"
"\n"
+ " --macho-min-os minos minimum os version for mach-o format(example: macos11.0)\n"
+ "\n"
" -w+x enable warning x (also -Wx)\n"
" -w-x disable warning x (also -Wno-x)\n"
" -w[+-]error promote all warnings to errors (also -Werror)\n"
diff --git a/output/macho.h b/output/macho.h
index 538c531e..6a5883e3 100644
--- a/output/macho.h
+++ b/output/macho.h
@@ -60,6 +60,7 @@
#define LC_SEGMENT 0x1
#define LC_SEGMENT_64 0x19
#define LC_SYMTAB 0x2
+#define LC_BUILD_VERSION 0x32
/* Symbol type bits */
#define N_STAB 0xe0
@@ -144,6 +145,20 @@
#define R_ABS 0
#define R_SCATTERED 0x80000000
+/* Known values for the platform field in LC_BUILD_VERSION */
+#define PLATFORM_MACOS 1
+#define PLATFORM_IOS 2
+#define PLATFORM_TVOS 3
+#define PLATFORM_WATCHOS 4
+#define PLATFORM_BRIDGEOS 5
+#define PLATFORM_MACCATALYST 6
+#define PLATFORM_IOSSIMULATOR 7
+#define PLATFORM_TVOSSIMULATOR 8
+#define PLATFORM_WATCHOSSIMULATOR 9
+#define PLATFORM_DRIVERKIT 10
+
+#define PLATFORM_INVALID 0
+
/* VM permission constants */
#define VM_PROT_NONE 0x00
#define VM_PROT_READ 0x01
diff --git a/output/outmacho.c b/output/outmacho.c
index d041df64..61f68fcf 100644
--- a/output/outmacho.c
+++ b/output/outmacho.c
@@ -64,6 +64,7 @@
#define MACHO_SYMCMD_SIZE 24
#define MACHO_NLIST_SIZE 12
#define MACHO_RELINFO_SIZE 8
+#define MACHO_BUILDVERSION_SIZE 24
#define MACHO_HEADER64_SIZE 32
#define MACHO_SEGCMD64_SIZE 72
@@ -215,6 +216,15 @@ static uint64_t seg_vmsize = 0;
static uint32_t seg_nsects = 0;
static uint64_t rel_padcnt = 0;
+/* build_version_platform information
+ PLATFORM_INVALID implies that build_version_platform won't emitted. */
+static uint32_t build_version_platform = PLATFORM_INVALID;
+/* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+static uint32_t build_version_minos = 0;
+
+/* used in nasm.c */
+bool macho_set_min_os(const char *str);
+
/*
* Functions for handling fixed-length zero-padded string
* fields, that may or may not be null-terminated.
@@ -1263,6 +1273,12 @@ static void macho_calculate_sizes (void)
}
}
+ /* for build_version_command */
+ if (build_version_platform != PLATFORM_INVALID) {
+ ++head_ncmds;
+ head_sizeofcmds = MACHO_BUILDVERSION_SIZE;
+ }
+
/* calculate size of all headers, load commands and sections to
** get a pointer to the start of all the raw data */
if (seg_nsects > 0) {
@@ -1647,6 +1663,16 @@ static void macho_write (void)
offset = fmt.header_size + head_sizeofcmds;
+ if (build_version_platform != PLATFORM_INVALID) {
+ /* emit build_version_command */
+ fwriteint32_t(LC_BUILD_VERSION, ofile);
+ fwriteint32_t(MACHO_BUILDVERSION_SIZE, ofile);
+ fwriteint32_t(build_version_platform, ofile);
+ fwriteint32_t(build_version_minos, ofile);
+ fwriteint32_t(0 /* sdk */, ofile);
+ fwriteint32_t(0 /* ntools */, ofile);
+ }
+
/* emit the segment load command */
if (seg_nsects > 0)
offset = macho_write_segment (offset);
@@ -2376,6 +2402,85 @@ static const struct dfmt macho64_df_dwarf = {
static const struct dfmt * const macho64_df_arr[2] =
{ &macho64_df_dwarf, NULL };
+bool macho_set_min_os(const char* str) {
+ nasm_assert(str != NULL);
+
+ const char* platform_ver = nasm_strdup(str);
+ const char* environment = "";
+ char* sep = strchr(platform_ver, '-');
+ if (sep != NULL) {
+ sep[0] = '\0';
+ environment = sep + 1;
+ }
+
+ const char* version = platform_ver;
+ while (*version) {
+ if (*version >= '0' && *version <= '9') {
+ break;
+ }
+ ++version;
+ }
+ if (*version == '\0') {
+ nasm_free((char*) platform_ver);
+ return false;
+ }
+
+ /* Mimic clang's target triple */
+ int platform = PLATFORM_INVALID;
+ if (strstr(platform_ver, "macos") == platform_ver) {
+ platform = PLATFORM_MACOS;
+ } else if ((strstr(platform_ver, "ios") == platform_ver)) {
+ if (environment[0] == '\0') {
+ platform = PLATFORM_IOS;
+ } else if ((strstr(environment, "simulator") == environment)) {
+ platform = PLATFORM_IOSSIMULATOR;
+ } else if ((strstr(environment, "catalyst") == environment)) {
+ platform = PLATFORM_MACCATALYST;
+ } else {
+ nasm_free((char*) platform_ver);
+ return false;
+ }
+ } else if ((strstr(platform_ver, "tvos") == platform_ver)) {
+ if (environment[0] == '\0') {
+ platform = PLATFORM_TVOS;
+ } else if ((strstr(environment, "simulator") == environment)) {
+ platform = PLATFORM_TVOSSIMULATOR;
+ } else {
+ nasm_free((char*) platform_ver);
+ return false;
+ }
+ } else if (xstrncmp("watchos", platform_ver) == 0) {
+ if (environment[0] == '\0') {
+ platform = PLATFORM_WATCHOS;
+ } else if ((strstr(environment, "simulator") == environment)) {
+ platform = PLATFORM_WATCHOSSIMULATOR;
+ } else {
+ nasm_free((char*) platform_ver);
+ return false;
+ }
+ } else if (xstrncmp("bridgeos", platform_ver) == 0) {
+ platform = PLATFORM_BRIDGEOS;
+ } else {
+ nasm_free((char*) platform_ver);
+ return false;
+ }
+
+ unsigned short major = 0, minor = 0, subminor = 0;
+ int count = sscanf(version, "%hu.%hu.%hu", &major, &minor, &subminor);
+ /* at least major and minor must be given */
+ if (count < 2) {
+ nasm_free((char*) platform_ver);
+ return false;
+ }
+
+ build_version_platform = platform;
+ build_version_minos =
+ ((major & 0xffff) << 16) | ((minor & 0xff) << 8) | (subminor & 0xff);
+
+ nasm_free((char*) platform_ver);
+ return true;
+}
+
const struct ofmt of_macho64 = {
"Mach-O x86-64 (Mach, including MacOS X and variants)",
"macho64",
--
2.30.0
More information about the Nasm-devel
mailing list