zoukankan      html  css  js  c++  java
  • Mp4V2与ffmpeg静态库符号冲突问题解决

    一、为什么静态符号会冲突

      无论macho二进制类型,还是Windows上的PE格式,还是Linux上的ELF格式,里面都是按照特定格式存放的一个程序的代码和数据

      比如Linux下的可执行文件格式,大致分为下面这些段

      参考:https://www.ibm.com/developerworks/cn/linux/l-excutff/    

      不同操作系统支持的可执行文件格式不一样,但是不同平台上面可执行文件执行的流程是一样的。读取可执行文件,分别解析不同段,并解析之后,映射到进程中,

      进程中的内存分布也是分段,这样方便数据组织和权限管理。

      不同的静态库文件,映射到进程之后,还存在一个软连接的过程,想象一下,一个函数在其他B库中实现,A要使用的时候,是怎么调用的。

      怎么知道B中方法的地址呢。

      在B库映射到进程中后,A方法调用这个函数(符号)之前,操作系统已经找到这个符号在进程中的地址,建立符号->之际函数入口点的过程,就是符号表映射的过程,

      这也是fishhook的原理,以上是我的理解。

    二、分析工具介绍

      有一个工具nm,能够用来分析二进制文件,可以扫描到可执行文件中的符号、以及相关信息。

    NAME
           nm - list symbols from object files
    
    SYNOPSIS
           nm [-A|-o|--print-file-name] [-a|--debug-syms]
              [-B|--format=bsd] [-C|--demangle[=style]]
              [-D|--dynamic] [-fformat|--format=format]
              [-g|--extern-only] [-h|--help]
              [-l|--line-numbers] [-n|-v|--numeric-sort]
              [-P|--portability] [-p|--no-sort]
              [-r|--reverse-sort] [-S|--print-size]
              [-s|--print-armap] [-t radix|--radix=radix]
              [-u|--undefined-only] [-V|--version]
              [-X 32_64] [--defined-only] [--no-demangle]
              [--plugin name] [--size-sort] [--special-syms]
              [--synthetic] [--target=bfdname]
              [objfile...]
    
    DESCRIPTION
           GNU nm lists the symbols from object files objfile....  If no object
           files are listed as arguments, nm assumes the file a.out.
    
           For each symbol, nm shows:
            # ... run man nm for detials.
    

      不同符号的不同类型

    ValueDescripitionNote
    A The symbol's value is absolute, and will not be changed by further linking. 符号绝对,链接过程不会改变
    B/b The symbol is in the uninitialized data section (known as BSS). 非初始化符号
    C The symbol is common. 公有符号,链接时会被同名符号覆盖
    D/d The symbol is in the initialized data section. 初始化符号
    G/g The symbol is in an initialized data section for small objects. 初始化符号,面向小数据访问优化
    I The symbol is an indirect reference to another symbol. 其它符号的间接引用
    N The symbol is a debugging symbol. 调试符号
    P The symbols is in a stack unwind section. 栈区符号(清空)
    R/r The symbol is in a read only data section. 符号只读
    S/s The symbol is in an uninitialized data section for small objects. 非初始化符号,面向小数据访问优化
    T/t The symbol is in the text (code) section. 代码区符号
    U The symbol is undefined. 未定义或在外部定义的符号
    u The symbol is a unique global symbol. 全局唯一,GNU保留符
    V/v The symbol is a weak object. 弱定义符(详见C++强弱符号定义)
    W/w The symbol is a weak symbol that has not been specifically tagged as a weak object symbol. emm...绕口令符号
    - The symbol is a stabs symbol in an a.out object file. stabs格式符号
    ? The symbol type is unknown, or object file format specific. NM也不认识的符号

      比如:(参考 https://www.jianshu.com/p/a86bd1b8e4a5
      
    rew@rew:/usr/lib64$ nm libpthread.a
    
    nptl-init.o:
                     U __default_pthread_attr
                     U __default_pthread_attr_lock
                     U _dl_cpuclock_offset
                     U _dl_get_tls_static_info
                     U _dl_init_static_tls
                     U _dl_pagesize
                     U _dl_wait_lookup_done
                     U __fork_generation
                     U __getrlimit
                     U __is_smp
                     U __libc_fatal
    0000000000000008 C __libc_multiple_threads_ptr
                     U __libc_pthread_init
                     U __libc_setup_tls
                     U __libc_sigaction
                     U __libc_stack_end
                     U __lll_lock_wait_private
                     U __lll_unlock_wake_private
    0000000000000000 b __nptl_initial_report_events
    00000000000001b0 T __nptl_set_robust
                     U __nptl_setxid_error
    0000000000000000 r nptl_version
    00000000000004b0 T __pthread_get_minstack
    00000000000001d0 T __pthread_initialize_minimal
    00000000000001d0 T __pthread_initialize_minimal_internal
    

      

    三、问题解决过程

      最近发现,米家App中新引入了一个Mp4V2的.a静态库后,ffmpeg工作不正常了,Xcode调试过程中没有任何信息,只能看到crash  

      

      经过一番思索,猜测可能是这个库和ffmpeg本来的库存在符号冲突,使用nm工具导出所有符号

      在静态库libmp4v2.a同级目录下面执行 命令

    nm -U libmp4v2.a  | grep  -v ' t ' | grep -v ' s ' | grep -v ' d ' |  grep -v ' b ' | awk '{print $3}' | tr -s '
    ' > symbol.txt
    

      看下symbol.txt的结果

     cat symbol.txt
    

      

      生成的符号结果很多,其中因为.a是fat结构,很多符号是冲突的。

      一些符号明显带有mp4v2的标记,不可能跟ffmpeg冲突,所以,要对结果过滤下

      编写一段脚本代码,过滤这个文本

      过滤掉Mp4相关,并且去重

    #!/usr/bin/env python3
    # _*_ coding:utf-8 _*_
    #
    # @Version : 1.0
    # @Time    : 2019/6/29 3:13
    # @Author  : ddyt
    # @File    : LessSymbol.py
    #
    # 符号表处理
    
    import cxxfilt
    
    if __name__ == '__main__':
        s = set()
        file = open("symbol.txt")
        fileLines = file.readlines()
        for line in fileLines:
            if "mp4" not in line and line.rstrip() not in s and "MP4" not in line:
                print(cxxfilt.demangle(line.rstrip()))
                s.add(line.rstrip())

     

     过滤结果  

       

      部分符号看起来很复杂,这个是C++类的方法经过编译器mangle之后生成的

      将所有内容进行demangle,打开 https://demangler.com/,输入脚本生成的结果,demangle

      可以看到一些复杂的符号,是C++ string的符号产生的,忽略掉这些符号

      

      可以看到一些特殊的方法

    _av_free
    _av_freep
    _av_log2
    _av_log2_16bit
    _av_malloc
    _av_mallocz
    _av_realloc
    _av_realloc_array
    _av_realloc_f
    _av_reallocp
    _av_reallocp_array
    _avio_w8
    _avio_wb16
    _avio_wb32
    _avio_write
    _ff_avc_find_startcode
    _ff_avc_parse_nal_units
    _ff_avc_parse_nal_units_buf
    _ff_golomb_vlc_len
    _ff_interleaved_dirac_golomb_vlc_code
    _ff_interleaved_golomb_vlc_len
    _ff_interleaved_se_golomb_vlc_code
    _ff_interleaved_ue_golomb_vlc_code
    _ff_isom_write_hvcc
    _ff_se_golomb_vlc_code
    _ff_ue_golomb_len
    _ff_ue_golomb_vlc_code
    _mov_assm_hvcc_data
    _mov_hvcc_add_nal_unit
    _mov_write_hev1_tag
    _mov_write_hvcc_tag
    

      这些带有ff前缀和av前缀的,就是来自ffmpeg,这些符号就是冲突的根源

    再看下crash时候的堆栈,最后一个方法avio_write在上面的符号中

      现在冲突的原因找到了,处理思路分为两种

      1、修改冲突的函数的名字

      2、使用宏定义来修改函数的名字

      这里采用第一种,使用Visual Code打开代码目录

      

      然后,针对可能冲突的符号,逐一全局查找替换

      

      

      到此,工作基本完成

      修改完毕之后,合并测试

  • 相关阅读:
    脚本绘图工具总结
    Windows Server 2012 磁盘管理之 简单卷、跨区卷、带区卷、镜像卷和RAID-5卷
    Java web项目 本地配置https调试
    Twitter的分布式自增ID算法snowflake (Java版)
    Redis压测命令
    Java读取txt文件信息并操作。
    安装配置adb工具及遇到的问题
    数据库逆向生成数据库表详细设计文档
    Java常用日期处理方法
    Date与String互相转换及日期的大小比较
  • 原文地址:https://www.cnblogs.com/doudouyoutang/p/11106725.html
Copyright © 2011-2022 走看看