How to define binary image architecture at runtime?

The crash log contains a Binary Images section with architecture information (armv6 / armv7) and an identifier for all loaded modules. How to determine this information at runtime? (at least for an executable application only)
NSBundle has an executableArchitectures method, but how to determine which architecture works?

+6
source share
3 answers

Time for a long answer. The machine headers of the dyld images in the application contain the information you are looking for. I added an example that I tested only for work, and nothing else, so I would not recommend inserting it directly into production code. What he does is he gets all the mach headers for all the currently loaded dyld images and prints output very similar to the Binary Images section in the crash log. The methods that I call are not thread safe. The only thing I am missing is the final address of the binary image, because I did not search how to find it.

main.m

#import <UIKit/UIKit.h> #include <string.h> #import <mach-o/loader.h> #import <mach-o/dyld.h> #import <mach-o/arch.h> void printImage(const struct mach_header *header) { uint8_t *header_ptr = (uint8_t*)header; typedef struct load_command load_command; const NXArchInfo *info = NXGetArchInfoFromCpuType(header->cputype, header->cpusubtype); //Print the architecture ex. armv7 printf("%s ", info->name); header_ptr += sizeof(struct mach_header); load_command *command = (load_command*)header_ptr; for(int i = 0; i < header->ncmds > 0; ++i) { if(command->cmd == LC_UUID) { struct uuid_command ucmd = *(struct uuid_command*)header_ptr; CFUUIDRef cuuid = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *((CFUUIDBytes*)ucmd.uuid)); CFStringRef suuid = CFUUIDCreateString(kCFAllocatorDefault, cuuid); CFStringEncoding encoding = CFStringGetFastestEncoding(suuid); //Print UUID printf("<%s> ", CFStringGetCStringPtr(suuid, encoding)); CFRelease(cuuid); CFRelease(suuid); break; } header_ptr += command->cmdsize; command = (load_command*)header_ptr; } } void printBinaryImages() { printf("Binary Images:\n"); //Get count of all currently loaded DYLD uint32_t count = _dyld_image_count(); for(uint32_t i = 0; i < count; i++) { //Name of image (includes full path) const char *dyld = _dyld_get_image_name(i); //Get name of file int slength = strlen(dyld); int j; for(j = slength - 1; j>= 0; --j) if(dyld[j] == '/') break; //strndup only available in iOS 4.3 char *name = strndup(dyld + ++j, slength - j); printf("%s ", name); free(name); const struct mach_header *header = _dyld_get_image_header(i); //print address range printf("0x%X - ??? ", (uint32_t)header); printImage(header); //print file path printf("%s\n", dyld); } printf("\n"); } int main(int argc, char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; printBinaryImages(); [pool release]; return retVal; } 

Output Example:

 Binary Images: TestBed 0x1000 - ??? i386 <E96D079C-E035-389D-AA12-71E968C76BFE> /Users/username/Library/Application Support/iPhone Simulator/4.3/Applications/6F64D9F8-9179-4E21-AE32-4D4604BE77E5/TestBed.app/TestBed UIKit 0x8000 - ??? i386 <72030911-362F-3E47-BAF3-ACD2CB6F88C0> /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/System/Library/Frameworks/UIKit.framework/UIKit Foundation 0x772000 - ??? i386 <EB718CBD-1D57-3D31-898D-7CFA9C172A46> /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/System/Library/Frameworks/Foundation.framework/Foundation CoreGraphics 0xA10000 - ??? i386 <D168A716-71F2-337A-AE0B-9DCF51AE9181> /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics libSystem.dylib 0xCAA000 - ??? i386 <8DF0AFCD-FFA5-3049-88E2-7410F8398749> /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/usr/lib/libSystem.dylib ... 
+16
source

For a quick answer about architecture, since you are building an application, you can check out some preprocessors to determine the current architecture for which your application is created. Make sure you check the most affordable version of the weapon, because each new version identifies all older versions.

 #if __arm__ #import <arm/arch.h> #ifdef __ARM_ARCH_6K__ //This is armv6 #endif //__ARM_ARCH_6K__ #endif //__arm__ 
+2
source

We can use the sysctl, sysctlbyname system call to get or set system information.

Code example:

 #import <sys/sysctl.h> #import <mach/machine.h> int32_t value = 0; size_t length = sizeof(value); sysctlbyname("hw.cputype", &value, &length, NULL, 0); if (value == CPU_TYPE_ARM64) { // arm64 } else if (value == CPU_TYPE_ARM) { // armv7/armv7s } else if (value == CPU_TYPE_X86) { // simulator } 

I just listed the most common arch in 2016. Look for "hw.cpusubtype" for more information, such as CPU_SUBTYPE_ARM_V6 CPU_SUBTYPE_ARM_V7 CPU_SUBTYPE_ARM_V7S

0
source

All Articles