美文网首页
Mach-O初探和链接

Mach-O初探和链接

作者: 雾中探雪 | 来源:发表于2021-03-08 16:31 被阅读0次
    Mach-O初探和链接
    1、Mach-O定义
    • Mach-O(Mach Object)是macOS、iOS、iPadOS存储程序和库的⽂件格式。对应系统通过应⽤⼆进制接⼝(application binary interface,缩写为ABI)来运⾏该格式的⽂件。
    • Mach-O格式⽤来替代BSD系统的a.out格式。Mach-O⽂件格式保存了在编译过程和链接过程中产⽣的机器代码和数据,从⽽为静态链接和动态链接的代码提供了单⼀⽂件格式
    • 可执⾏⽂件(Mach-O)调⽤过程:
    1. 调⽤`fork`函数,创建⼀个`process`
    2. 调⽤`execve`或其衍⽣函数,在该进程上加载,执⾏我们的`Mach-O`⽂件
    // 注:当我们调⽤时`execve`(程序加载器),内核实际上在执⾏以下操作:1. 将⽂件加载到内存 2. 开始分析`Mach-O`中的`mach_header`,以确认它是有效的`Mach-O`⽂件
    
    • 问题:Mach-O中是不是都是二进制代码?是的,就是二进制代码。
    • 终端中解析Mach-O文件命令:
    objdump --macho --private-headers /users/zengca/..(Mach-o文件路径)
    
    2、 链接
    • 链接的本质就是把多个⽬标⽂件组合成⼀个⽂件
    • 链接过程分析图


      链接过程.png
    3、Symbol Table(符号表)
    • 1、符号表定义:
      符号表可以提供应用软件及其动态加载的库中引用的函数、类、方法等信息。通常,符号表中包含比类转储更多的信息,并且还包含了应用软件使用的C或者C++ 组件的信息。就好比你要去某个城市某个地方,首先你得需要一张地图才能找得到某个地方吧。符号表就是这张地图。
    Symbol Table:就是⽤来保存符号。
    String Table:就是⽤来保存符号的名称。
    Indirect Symbol Table:间接符号表。保存使⽤的外部符号。更准确⼀点就是使⽤的外部动态库的符号。是Symbol Table的⼦集。
    
    • 2、nm命令
      • 作用:nm命令作用就是显示目标文件的符号表,文件对象可以是静态库、动态库、编译目标文件、可执行程序等任何包含符号信息的文件类型。
      • 功能:nm命令可以列出一个函数库文件(.o .a .so)中的符号表。所谓符号,通常指定义出的函数,全局变量等等。它对于静态的函数库和共享的函数库都起作用。nm命令显示的信息用于调试库和可执行文件,对于一个给定的函数库,nm命令可以列出函数库中定义的所有符号,包括每个符号的值和类型。还可以给出在原程序中这个函数(符号)是在多少行定义的,不过这必须要求编译该函数库的时候加“-l”选项。
      • 使用:nm [选项] [文件列表(库文件/目标文件/可执行文件)]
    $ nm helloworld
    0000bf08 s  stub helpers
    0000be00 t -[SaySomething say:]
             U _NSClassFromString
             U _NSSelectorFromString
    0000c110 S _NXArgc
    0000c114 S _NXArgv
             U _OBJC_CLASS_$_NSObject
    0000c0fc S _OBJC_CLASS_$_SaySomething
             U _OBJC_METACLASS_$_NSObject
    0000c0e8 S _OBJC_METACLASS_$_SaySomething
             U ___CFConstantStringClassReference
    0000c11c S ___progname
    00004000 T __mh_execute_header
             U __objc_empty_cache
    0000c118 S _environ
             U _exit
    0000be44 T _main
             U _objc_autoreleasePoolPop
             U _objc_autoreleasePoolPush
             U _objc_msgSend
             U _printf
    0000c018 s _pvars
             U dyld_stub_binder
    0000bdd4 T start
    
    • 有用的options:
    第一列就是内存地址,没有什么好解释的。
    第二列这些符号都什么意思呢?
    对于每一个富豪来说,其类型如果是小写的,则表明符号是local的;大写则表明符号是global 的。
    A  该符号的值是绝对的,在以后的链接过程中,不允许进行改变,这样的符号之,尝尝出现在中断向量(终端服务程序的入口地址)中,列入用符号来表示中断向量函数在中断 向量表中的位置。
    B  该符号的值出现在非初始化数据段中(bss)。例如,在一个文件中定义全局static int  a。则该响亮符号 a  的类型为b,位于bss section 中。
    C  该符号为common。common symbol 是未初始化数据段。该符号没有包含于一个普通section 中。只有在连接过程中才进行分配。符号的指标是该符号的字节数。
    D  该符号位于初始化数据段中。一般来说。分配到data section 中。例如,定义 int  arr[5] = {9600,19200,28400,57600,115200},会分配到初始化数据段中。
    G  该符号也位于初始化数据段中。主要用于small Object 提高访问small Object 的一种方式。
    I  该符号是对另一个符号的间接引用。
    N  该符号位于只读数据区,例如定义全局const int test[] = {123,123};则test 就是一个只读数据区的符号。
    S  该符号位于非初始化数据区,用于small Object。
    T  该符号位于代码区 text  section 。
    U  该符号在当前文件中是未定义的,即该符号的定义在别的文件中。
    V  该符号是一个weak Object 。
    
    好了,现在来解释一下上边的一个具体信息。
    0000be00 t -[SaySomething say:]
             U _NSClassFromString
             U _NSSelectorFromString
    
    1、表示位于0x0000be00 地址中,say 方法是在本文件有定义的,所以是小写的t,其次,由于OC 是种动态语言,在调用方法时,根据方法名称来确定方法的唯一性,因此类和方法的名称必须存放在一个定法 ,如上SaySomething 类和say 方法存放在代码区,因此,他们的符号为t。
    2、NSClassFromString 和NSSelectorFromString 方法是从Objective-C 语言库中动态加载起来的。在这个文件中没有定义,所以他们的符号为U。
    
    4、重定向

    Target—>Build Phases—>Run Script—>echo "hello" >/dev/ttys000

    重定向.png
    注:/dev/ttys000 是当前终端的名称,在终端中执行tty就可以看到当前终端名称
    5、使用脚本运行命令
    • (1)这里提前做好了一个脚本文件xcode_run_cmd.sh,内容如下:
    #!/bin/sh
    
    
    RunCommand() {
      #判断全局字符串VERBOSE_SCRIPT_LOGGING是否为空。-n string判断字符串是否非空
      #[[是 bash 程序语言的关键字。用于判断
      if [[ -n "$VERBOSE_SCRIPT_LOGGING" ]]; then
        #作为一个字符串输出所有参数。使用时加引号"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数
          if [[ -n "$TTY" ]]; then
              echo "♦ $@" 1>$TTY
          else
              echo "♦ $*"
          fi
          echo "------------------------------------------------------------------------------" 1>$TTY
      fi
      #与$*相同。但是使用时加引号,并在引号中返回每个参数。"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数
      if [[ -n "$TTY" ]]; then
          echo `$@ &>$TTY`
      else
          "$@"
      fi
      #显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
      return $?
    }
    
    EchoError() {
        #在shell脚本中,默认情况下,总是有三个文件处于打开状态,标准输入(键盘输入)、标准输出(输出到屏幕)、标准错误(也是输出到屏幕),它们分别对应的文件描述符是0,1,2
        # >  默认为标准输出重定向,与 1> 相同
        # 2>&1  意思是把 标准错误输出 重定向到 标准输出.
        # &>file  意思是把标准输出 和 标准错误输出 都重定向到文件file中
        # 1>&2 将标准输出重定向到标准错误输出。实际上就是打印所有参数已标准错误格式
        if [[ -n "$TTY" ]]; then
            echo "$@" 1>&2>$TTY
        else
            echo "$@" 1>&2
        fi
        
    }
    
    RunCMDToTTY() {
        if [[ ! -e "$TTY" ]]; then
            EchoError "=========================================="
            EchoError "ERROR: Not Config tty to output."
            exit -1
        fi
        
        if [[ -n "$CMD" ]]; then
            RunCommand "$CMD" ${CMD_FLAG}
        else
            EchoError "=========================================="
            EchoError "ERROR:Failed to run CMD. THE CMD must not null"
        fi
    }
    
    
    RunCMDToTTY
    
    
    • (2)将脚本文件配置到Run Script中如下图:


      脚本文件配置.png
    • (3)xcconfig文件中配置脚本文件需要的参数
      • 创建xcconfig文件,创建过程如上述,xcconfig创建和配置。这里我们创建的是RunCMD.xcconfig文件,将其配置在Debug模式下。内容如下:
    //  TTY = 终端
    //  CMD = 运行的命令
    //  CMD_FLAG = 运行命令的参数
    
    CMD = nm
    CMD_FLAG = -pa ${MACHO_PATH}
    TTY = /dev/ttys000
    MACHO_PATH=${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/*
    
    // nm
    // -p: 不排序
    // -a: 显示所有符号,除了调试符号
    // -m:显示(N_SECT)符号,格式(seg-ment_name, section_name) (external non-
    // external) (undefined), (common), (absolute) (indirect)
    
    // objdump
    // --macho --syms
    // --exports-trie :导出符号
    
    // -Xlinker  在GCC中用来给连接器传递参数,每次只能传递一个参数(如:-Xlinker -S ),如果传递多个参数需多次传递(如:-Xlinker -S -Xlinker _cat_NSLog或可简写为-Xlinker -S=_cat_NSLog)。
    // -Wl 在GCC中用来给连接器传递参数,可以传递多个参数(如:-Wl,-Map,output.map)。
    // -S 去除输出文件中的调试信息
    
    // -O1 -Oz 生成目标文件  编译时优化
    // 后面两步就是在操作符号
    // dead code strip  死代码剥离实际上也是在剥离符号  链接时
    // strip 剥离符号  修改已经生成的Mach-O文件
    

    运行结果:

    Last login: Mon Jan 18 13:42:42 on ttys000
    zengcai@Mac-mini ~ % 0000000100003f40 t _weak_hidden_function
    0000000100008008 d __dyld_private
    0000000100008014 d _static_init_value
    0000000100008018 d _hidden_y
    0000000100008030 b _static_uninit_value
    0000000100008040 s _default_x
    0000000000000000 - 00 0000    SO /Users/zengcai/Downloads/逻辑学习/强化班第一节课资料/完成代码/MachOAndSymbol/
    0000000000000000 - 00 0000    SO main.m
    0000000060050b13 - 03 0001   OSO /Users/zengcai/Library/Developer/Xcode/DerivedData/MachOAndSymbol-aiyqlpfqaarxnvcresdhogckdoqi/Build/Intermediates.noindex/MachOAndSymbol.build/Debug/MachOAndSymbol.build/Objects-normal/x86_64/main.o
    0000000100003ec0 - 01 0000 BNSYM
    0000000100003ec0 - 01 0000   FUN _main
    000000000000003f - 00 0000   FUN
    000000000000003f - 01 0000 ENSYM
    0000000000000000 - 00 0000  GSYM _global_init_value
    0000000100008014 - 0a 0000 STSYM _static_init_value
    0000000100008030 - 0b 0000 STSYM _static_uninit_value
    0000000000000000 - 00 0000  GSYM _global_uninit_value
    0000000000000000 - 00 0000  GSYM _default_x
    0000000000000000 - 01 0000    SO
    0000000000000000 - 00 0000    SO /Users/zengcai/Downloads/逻辑学习/强化班第一节课资料/完成代码/MachOAndSymbol/
    0000000000000000 - 00 0000    SO WeakImportSymbol.m
    0000000060052666 - 03 0001   OSO /Users/zengcai/Library/Developer/Xcode/DerivedData/MachOAndSymbol-aiyqlpfqaarxnvcresdhogckdoqi/Build/Intermediates.noindex/MachOAndSymbol.build/Debug/MachOAndSymbol.build/Objects-normal/x86_64/WeakImportSymbol.o
    0000000100003f00 - 01 0000 BNSYM
    0000000100003f00 - 01 0000   FUN _weak_import_function
    0000000000000017 - 00 0000   FUN
    0000000000000017 - 01 0000 ENSYM
    0000000000000000 - 01 0000    SO
    0000000000000000 - 00 0000    SO /Users/zengcai/Downloads/逻辑学习/强化班第一节课资料/完成代码/MachOAndSymbol/
    0000000000000000 - 00 0000    SO WeakSymbol.m
    0000000060050b12 - 03 0001   OSO /Users/zengcai/Library/Developer/Xcode/DerivedData/MachOAndSymbol-aiyqlpfqaarxnvcresdhogckdoqi/Build/Intermediates.noindex/MachOAndSymbol.build/Debug/MachOAndSymbol.build/Objects-normal/x86_64/WeakSymbol.o
    0000000100003f20 - 01 0000 BNSYM
    0000000100003f20 - 01 0000   FUN _weak_function
    0000000000000020 - 00 0000   FUN
    0000000000000020 - 01 0000 ENSYM
    0000000100003f40 - 01 0000 BNSYM
    0000000100003f40 - 01 0000   FUN _weak_hidden_function
    0000000000000017 - 00 0000   FUN
    0000000000000017 - 01 0000 ENSYM
    0000000000000000 - 01 0000    SO
    0000000000000000 - 00 0000    SO /Users/zengcai/Downloads/逻辑学习/强化班第一节课资料/完成代码/MachOAndSymbol/
    0000000000000000 - 00 0000    SO VisibilitySymbol.m
    0000000060050b0f - 03 0001   OSO /Users/zengcai/Library/Developer/Xcode/DerivedData/MachOAndSymbol-aiyqlpfqaarxnvcresdhogckdoqi/Build/Intermediates.noindex/MachOAndSymbol.build/Debug/MachOAndSymbol.build/Objects-normal/x86_64/VisibilitySymbol.o
    0000000000000000 - 00 0000  GSYM _hidden_y
    0000000000000000 - 00 0000  GSYM _default_y
    0000000000000000 - 00 0000  GSYM _protected_y
    0000000000000000 - 01 0000    SO
    0000000100000000 T __mh_execute_header
    0000000100008020 D _default_y
    0000000100008010 D _global_init_value
    0000000100008038 S _global_uninit_value
    0000000100003ec0 T _main
    0000000100008028 D _protected_y
    0000000100003f20 T _weak_function
    0000000100003f00 T _weak_import_function
                     U _NSLog
                     U ___CFConstantStringClassReference
                     U dyld_stub_binder
    0000000100003f40 t _weak_hidden_function
    0000000100008008 d __dyld_private
    0000000100008014 d _static_init_value
    0000000100008018 d _hidden_y
    0000000100008030 b _static_uninit_value
    0000000100008040 s _default_x
    0000000000000000 - 00 0000    SO /Users/zengcai/Downloads/逻辑学习/强化班第一节课资料/完成代码/MachOAndSymbol/
    0000000000000000 - 00 0000    SO main.m
    000000006005268b - 03 0001   OSO /Users/zengcai/Library/Developer/Xcode/DerivedData/MachOAndSymbol-aiyqlpfqaarxnvcresdhogckdoqi/Build/Intermediates.noindex/MachOAndSymbol.build/Debug/MachOAndSymbol.build/Objects-normal/x86_64/main.o
    0000000100003ec0 - 01 0000 BNSYM
    0000000100003ec0 - 01 0000   FUN _main
    000000000000003f - 00 0000   FUN
    000000000000003f - 01 0000 ENSYM
    0000000000000000 - 00 0000  GSYM _global_init_value
    0000000100008014 - 0a 0000 STSYM _static_init_value
    0000000100008030 - 0b 0000 STSYM _static_uninit_value
    0000000000000000 - 00 0000  GSYM _global_uninit_value
    0000000000000000 - 00 0000  GSYM _default_x
    0000000000000000 - 01 0000    SO
    0000000000000000 - 00 0000    SO /Users/zengcai/Downloads/逻辑学习/强化班第一节课资料/完成代码/MachOAndSymbol/
    0000000000000000 - 00 0000    SO WeakImportSymbol.m
    000000006005268b - 03 0001   OSO /Users/zengcai/Library/Developer/Xcode/DerivedData/MachOAndSymbol-aiyqlpfqaarxnvcresdhogckdoqi/Build/Intermediates.noindex/MachOAndSymbol.build/Debug/MachOAndSymbol.build/Objects-normal/x86_64/WeakImportSymbol.o
    0000000100003f00 - 01 0000 BNSYM
    0000000100003f00 - 01 0000   FUN _weak_import_function
    0000000000000017 - 00 0000   FUN
    0000000000000017 - 01 0000 ENSYM
    0000000000000000 - 01 0000    SO
    0000000000000000 - 00 0000    SO /Users/zengcai/Downloads/逻辑学习/强化班第一节课资料/完成代码/MachOAndSymbol/
    0000000000000000 - 00 0000    SO WeakSymbol.m
    000000006005268b - 03 0001   OSO /Users/zengcai/Library/Developer/Xcode/DerivedData/MachOAndSymbol-aiyqlpfqaarxnvcresdhogckdoqi/Build/Intermediates.noindex/MachOAndSymbol.build/Debug/MachOAndSymbol.build/Objects-normal/x86_64/WeakSymbol.o
    0000000100003f20 - 01 0000 BNSYM
    0000000100003f20 - 01 0000   FUN _weak_function
    0000000000000020 - 00 0000   FUN
    0000000000000020 - 01 0000 ENSYM
    0000000100003f40 - 01 0000 BNSYM
    0000000100003f40 - 01 0000   FUN _weak_hidden_function
    0000000000000017 - 00 0000   FUN
    0000000000000017 - 01 0000 ENSYM
    0000000000000000 - 01 0000    SO
    0000000000000000 - 00 0000    SO /Users/zengcai/Downloads/逻辑学习/强化班第一节课资料/完成代码/MachOAndSymbol/
    0000000000000000 - 00 0000    SO VisibilitySymbol.m
    000000006005268b - 03 0001   OSO /Users/zengcai/Library/Developer/Xcode/DerivedData/MachOAndSymbol-aiyqlpfqaarxnvcresdhogckdoqi/Build/Intermediates.noindex/MachOAndSymbol.build/Debug/MachOAndSymbol.build/Objects-normal/x86_64/VisibilitySymbol.o
    0000000000000000 - 00 0000  GSYM _hidden_y
    0000000000000000 - 00 0000  GSYM _default_y
    0000000000000000 - 00 0000  GSYM _protected_y
    0000000000000000 - 01 0000    SO
    0000000100000000 T __mh_execute_header
    0000000100008020 D _default_y
    0000000100008010 D _global_init_value
    0000000100008038 S _global_uninit_value
    0000000100003ec0 T _main
    0000000100008028 D _protected_y
    0000000100003f20 T _weak_function
    0000000100003f00 T _weak_import_function
                     U _NSLog
                     U ___CFConstantStringClassReference
                     U dyld_stub_binder
    
    • 其中包含太多调试信息,我们可以使用-S命令去除调试信息,所以在RunCMD.xcconfig文件添加:OTHER_LDFLAGS = -Xlinker -S 具体如下:
    CMD = nm
    CMD_FLAG = -pa ${MACHO_PATH}
    TTY = /dev/ttys000
    OTHER_LDFLAGS = -Xlinker -S
    MACHO_PATH=${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/*
    

    运行结果:

    0000000100003f40 t _weak_hidden_function
    0000000100008008 d __dyld_private
    0000000100008014 d _static_init_value
    0000000100008018 d _hidden_y
    0000000100008030 b _static_uninit_value
    0000000100008040 s _default_x
    0000000100000000 T __mh_execute_header
    0000000100008020 D _default_y
    0000000100008010 D _global_init_value
    0000000100008038 S _global_uninit_value
    0000000100003ec0 T _main
    0000000100008028 D _protected_y
    0000000100003f20 T _weak_function
    0000000100003f00 T _weak_import_function
                     U _NSLog
                     U ___CFConstantStringClassReference
                     U dyld_stub_binder
    
    • 总结:上面是通过运行脚本的方式执行命令,需要通过xcconfig文件配置脚本所需参数,同时可以在xcconfig文件添加符号来进行操作。通过符号可以用来优化包体大小等多种用图。

    相关文章

      网友评论

          本文标题:Mach-O初探和链接

          本文链接:https://www.haomeiwen.com/subject/smtuzktx.html