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 '\n' > 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打開代碼目錄

  

  然後,針對可能衝突的符號,逐一全局查找替換

  

  

  到此,工作基本完成

  修改完畢之後,合併測試

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章