NXGetLocalArchInfo() returns incorrect architecture type.

Questions and Answers about all things *OS (macOS, iOS, tvOS, watchOS)

NXGetLocalArchInfo() returns incorrect architecture type.

Postby nitinJami » Mon Aug 31, 2015 9:22 pm

Hi Jon,

First of all, I attended your "OSX/iOS Internals -- A RE perspective" training recently held in SF and I would like to thank you for hosting the training.

NXGetLocalArchInfo() from the <mach-o/arch.h> incorrectly returns as a 32-bit architecture on my 2013 MBP. It returns the following "Intel 80486 7/4 Little-Endian" for description, cputype, cpusubtype. Moreover, the $ arch tool also returns i386.

So, my question is what other mechanism/information/tool does the system use to match the binary to the architecture for a Fat binary?
Posts: 3
Joined: Mon Aug 31, 2015 8:58 pm

Re: NXGetLocalArchInfo() returns incorrect architecture type

Postby morpheus » Mon Aug 31, 2015 9:40 pm

First, you're more than welcome. We're planning a second training now around December, so I hope the word gets out :)

Second, NXGetLocalArchInfo and arch itself were always kind of weird. They both returned "486" and "i386" for the longest time for a while, before Apple indeed fixed them. The "arch" command indeed uses NXGLA, and NXGLA itself, you can see if you try the following:

Code: Select all
bash-3.2# export ARCH=x86_64; for i in /usr/lib/system/*.dylib; do if jtool -S $i | grep "T _NXGetLocalArch"; then echo found in $i; fi ; done
00000000000010d5 T _NXGetLocalArchInfo

Then using otool (because jtool lamentably doesn't support Intel), disassemble and see:

Code: Select all
bash-3.2# otool -tV /usr/lib/system/libmacho.dylib  | more
(__TEXT,__text) section
00000000000010c8        pushq   %rbp
00000000000010c9        movq    %rsp, %rbp
00000000000010cc        leaq    _ArchInfoTable(%rip), %rax
00000000000010d3        popq    %rbp
00000000000010d4        retq
00000000000010d5        pushq   %rbp
00000000000010d6        movq    %rsp, %rbp
00000000000010d9        pushq   %r14
00000000000010db        pushq   %rbx
00000000000010dc        subq    $0x40, %rsp
00000000000010e0        movl    $0xc, -0x44(%rbp)
00000000000010e7        callq   0x58aa                  ## symbol stub for: _mach_host_self
00000000000010ec        movl    %eax, %ebx
00000000000010ee        leaq    -0x40(%rbp), %rdx
00000000000010f2        leaq    -0x44(%rbp), %rcx
00000000000010f6        movl    $0x1, %esi
00000000000010fb        movl    %ebx, %edi
00000000000010fd        callq   0x58a4                  ## symbol stub for: _host_info
0000000000001102        movl    %eax, %r14d
0000000000001105        movq    0x4f04(%rip), %rax      ## literal pool symbol address: _mach_task_self_
000000000000110c        movl    (%rax), %edi
000000000000110e        movl    %ebx, %esi
0000000000001110        callq   0x58b0                  ## symbol stub for: _mach_port_deallocate
0000000000001115        xorl    %eax, %eax
0000000000001117        testl   %r14d, %r14d
000000000000111a        jne     0x113d
000000000000111c        movl    -0x34(%rbp), %edi
000000000000111f        movl    -0x30(%rbp), %esi
0000000000001122        cmpl    $0x6, %edi
0000000000001125        jne     0x1138
0000000000001127        cmpl    $0x1, %esi
000000000000112a        jne     0x1138
000000000000112c        movl    $0x3, -0x30(%rbp)
0000000000001133        movl    $0x3, %esi
0000000000001138        callq   _NXGetArchInfoFromCpuType
000000000000113d        addq    $0x40, %rsp
0000000000001141        popq    %rbx
0000000000001142        popq    %r14
0000000000001144        popq    %rbp
0000000000001145        retq

So note this is coming from host_info, which is (if you follow this exercise) a call to the mach_host primitive (message #200). To corroborate, try your hostinfo command and you will likely see the same "486".

In newer machines, and on 10.10 (possibly 10.9) they fixed it, so mine for example returns:

bash-3.2# /tmp/a
bash-3.2# cat /tmp/a.c
#include <mach-o/arch.h>
#if 0
extern const NXArchInfo *NXGetLocalArchInfo(void);

typedef struct {
const char *name;
cpu_type_t cputype;
cpu_subtype_t cpusubtype;
enum NXByteOrder byteorder;
const char *description;
} NXArchInfo;

int main (int argc, char **argv)

NXArchInfo *nxai = NXGetLocalArchInfo ();
printf("%s\n", nxai->name);


As for how one gets the exact architecture -- that's either via the default in-kernel matching of the architecture (the FAT image activator somewhere in kern_exec.c loops over the FAT architectures), or via arguments to posix_spawn - you can specify the binpref attribute for that.

Site Admin
Posts: 697
Joined: Thu Apr 11, 2013 6:24 pm

Re: NXGetLocalArchInfo() returns incorrect architecture type

Postby nitinJami » Mon Aug 31, 2015 9:58 pm

Hi Jon,

That makes sense. hostinfo does return i486 on my machine.

So, ultimately the system does not only rely on NXGLA to determine the architecture and then load the appropriate binary from a fat binary. It considers other parameters to match the correct architecture?

$ uname -m returns x86_64
Posts: 3
Joined: Mon Aug 31, 2015 8:58 pm

Re: NXGetLocalArchInfo() returns incorrect architecture type

Postby nitinJami » Tue Sep 01, 2015 1:04 am

I ran the commands and your program on a new MBP and like you said, Apple indeed fixed it. Thanks a lot for clearing up my question, Jon.
Posts: 3
Joined: Mon Aug 31, 2015 8:58 pm

Return to Questions and Answers

Who is online

Users browsing this forum: No registered users and 3 guests