想知道nm命令的实现原理吗---分析AIX平台下ELF文件的符号表

简介: 在AIX及其他unix/linux平台上,我们可以使用nm, objdump和readelf来分析ELF文件的符号表。具体使用方式是:nm objfile objdump -x objfile (或其他选项)readelf -a objfile但我们有时候需要在程序中来分析某个ELF文件(比如当前进程)的符号表,进行处理。
在AIX及其他unix/linux平台上,我们可以使用nm, objdump和readelf来分析ELF文件的符号表。具体使用方式是:
nm objfile
objdump -x objfile (或其他选项)
readelf -a objfile

但我们有时候需要在程序中来分析某个ELF文件(比如当前进程)的符号表,进行处理。这里针对AIX平台介绍附件中的代码所使用的方法来实现该功能。
附件中的C++代码巧妙利用了AIX提供的系统调用来读出ELF文件的符号表,它以面向对象的方式提供了如下接口:

  1. class XCOFFParser;
  2. //void * is SCNHDR * for 32 bit and SCNHDR_64 for 64 bit.
  3. //Return 0, contiue. Return 1: break the current parse.
  4. typedef int (*SectionCallback)(void *param, XCOFFParser *parser, int iIndex, void *secHeader);

  5. //void * is SYMENT * for 32 bit and SYMENT_64 for 64 bit.
  6. //Return 0, contiue. Return 1: break the current parse.
  7. typedef int (*SymbolCallback)(void *param, XCOFFParser *parser, int iIndex, char *symName, void *symEntry);

  8. enum XCOFF_SECTION{SECTION_TEXT=0, SECTION_DATA, SECTION_BSS, SECTION_DEBUG, SECTION_LOADER};
  9. struct SectionInfo
  10. {
  11.     XCOFF_SECTION sectionType;
  12.     int sectionNum;
  13.     char sectionName[MAX_SECTION_NAME_LENGTH];
  14. };

  15. class XCOFFParser
  16. {
  17. public:
  18.     XCOFFParser(char *fileName)
  19.     {
  20.         strcpy(m_strFileName, fileName);
  21.         m_ldPointer = NULL;
  22.         m_bIs64 = 0;
  23.         m_lSections = m_lSymbols = 0;
  24.         memset(m_sections, -1, sizeof(m_sections));
  25.     }

  26.     virtual ~XCOFFParser();
  27.     

  28.     
  29.     int InitParser();
  30.     
  31.     int ParseSections(SectionCallback pfnCallback, void *param, int iIncludeDep=0);
  32.     int ParseSymbols(SymbolCallback pfnCallback, void *param, int iIncludeDep=0);
  33.     int DeinitParser();

  34.     int Is64Bit()
  35.     {
  36.         return m_bIs64;
  37.     }
  38.     
  39.     char *GetFileName(char *buf) const
  40.     {
  41.         strcpy(buf, m_strFileName);
  42.         return buf;
  43.     }

  44.     long GetSectionsNumber() const
  45.     {
  46.         return m_lSections;
  47.     }

  48.     long GetSymbolsNumber() const
  49.     {
  50.         return m_lSymbols;
  51.     }

  52.     int IsDebugSymbol(void *symEntry)
  53.     {
  54.         if(m_bIs64)
  55.         {
  56.             return ((SYMENT_64 *)symEntry)->n_scnum == N_DEBUG;
  57.         }
  58.         return ((SYMENT *)symEntry)->n_scnum == N_DEBUG;
  59.     }

  60.     int IsABSSymbol(void *symEntry)
  61.     {
  62.         if(m_bIs64)
  63.         {
  64.             return ((SYMENT_64 *)symEntry)->n_scnum == N_ABS;
  65.         }
  66.         return ((SYMENT *)symEntry)->n_scnum == N_ABS;
  67.     }


  68.     int IsUndefSymbol(void *symEntry)
  69.     {
  70.         if(m_bIs64)
  71.         {
  72.             return ((SYMENT_64 *)symEntry)->n_scnum == N_UNDEF;
  73.         }
  74.         return ((SYMENT *)symEntry)->n_scnum == N_UNDEF;
  75.     }

  76.     int IsDefinedSymbol(void *symEntry)
  77.     {
  78.         int iInMem = (m_bIs64? ((SYMENT_64 *)symEntry)->n_sclass C_BLOCK:((SYMENT *)symEntry)->n_sclass C_BLOCK);
  79.         return !IsDebugSymbol(symEntry) && !IsABSSymbol(symEntry)
  80.                 && !IsUndefSymbol(symEntry) && iInMem;
  81.     }

  82.     int IsTextSymbol(void *symEntry)//Functions' symbol
  83.     {
  84.         if(m_bIs64)
  85.         {
  86.             return ((SYMENT_64 *)symEntry)->n_scnum == m_sections[SECTION_TEXT].sectionNum;
  87.         }
  88.         return ((SYMENT *)symEntry)->n_scnum == m_sections[SECTION_TEXT].sectionNum;
  89.     }

  90.        int IsDataSymbol(void *symEntry)//data symbol
  91.     {
  92.         if(m_bIs64)
  93.         {
  94.             return ((SYMENT_64 *)symEntry)->n_scnum == m_sections[SECTION_DATA].sectionNum;
  95.         }
  96.         return ((SYMENT *)symEntry)->n_scnum == m_sections[SECTION_DATA].sectionNum;
  97.     }

  98.     int IsBssSymbol(void *symEntry)
  99.     {
  100.         if(m_bIs64)
  101.         {
  102.             return ((SYMENT_64 *)symEntry)->n_scnum == m_sections[SECTION_BSS].sectionNum;
  103.         }
  104.         return ((SYMENT *)symEntry)->n_scnum == m_sections[SECTION_BSS].sectionNum;
  105.     }
  106. /*
  107.     int IsDebugSymbol(SYMENT *symEntry)
  108.     {
  109.         return symEntry->n_scnum == m_sections[SECTION_DEBUG].sectionNum;
  110.     }
  111. */

  112.     
  113. protected:
  114.     char m_strFileName[MAX_PATH_LEN];    
  115.     LDFILE* m_ldPointer;
  116.     int m_bIs64;
  117.     long m_lSections, m_lSymbols;

  118.     SectionInfo m_sections[MAX_SECTIONS];
  119. };
示例程序:
  1. #include
  2. #include "xcoff_parser.h"

  3. static int SymbolReadDefinedFuncs(void *param, XCOFFParser *parser, int iIndex, char *symName, void *symEntry)
  4. {
  5.     //printf("In callback\n");
  6.     if(strlen(symName) > 0 && parser->IsDefinedSymbol(symEntry) && parser->IsTextSymbol(symEntry))
  7.     {
  8.         //It's a function definition, let's store it into the map
  9.         printf("Defined function name:%s, address:%p\n", symName,
  10.                             parser->Is64Bit()? ((SYMENT_64 *)symEntry)->n_value: ((SYMENT *)symEntry)->n_value);
  11.         
  12.     }
  13.     return 0;
  14. }

  15. int main(int argc, char *argv[])
  16. {
  17.      XCOFFParser parser(buf);
  18.      int ret = parser.InitParser();
  19.      if(ret != ERROR_XCOFF_SUCCESS)
  20.      {
  21.          printf("XCOFFParser::InitParser failed:%d.\n", ret);
  22.         return ret;
  23.      }
  24.      ret = parser.ParseSections(NULL, NULL);
  25.      if(ret != ERROR_XCOFF_SUCCESS)
  26.      {
  27.          printf("XCOFFParser::ParseSections failed:%d.\n", ret);
  28.         return ret;
  29.      }

  30.      ret = parser.ParseSymbols(SymbolReadDefinedFuncs, NULL);
  31.      if(ret != ERROR_XCOFF_SUCCESS)
  32.      {
  33.          printf("XCOFFParser::ParseSymbols failed:%d.\n", ret);
  34.         return ret;
  35.      }
  36.      return 0;
  37. }


xcoff_parser中所使用到的主要系统调用:
  1. LDFILE *ldopen( char *, LDFILE * );
  2. int ldfhread( LDFILE *, void * );
  3. int ldshread( LDFILE *, unsigned short, void * );
  4. int ldtbread( LDFILE *, int, void * );
  5. int ldclose( LDFILE * );

zip.gif xcoff_parser.zip  

当看完下面这本书之后,你会发现你也可以实现这个功能:
《返璞归真--UNIX技术内幕》

目录
相关文章
|
Linux Windows
PE格式:实现ELF结构解析工具
ELF文件格式,是一个开放的可执行文件和链接文件格式,其主要工作在Linux系统上,是一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件,ELF文件格式类似于PE格式,但比起PE结构来ELF结构显得更加的简单,Linux文件结构相比于Windows结构来说简单一些.
249 0
|
IDE Linux 编译器
ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)(上)
ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)
386 1
ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)(上)
|
Ubuntu C语言 C++
ubuntu编译高阶数组出现段错误(核心已转储)问题
在ubuntu中编译C语言不允许直接定义高阶数组如: int arr[3000][3000];
ubuntu编译高阶数组出现段错误(核心已转储)问题
|
C语言
ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)(中)
ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)
124 0
|
编译器 C语言
ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)(下)
ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)
118 0
|
C语言
ARM架构与编程(基于I.MX6ULL): 代码重定位(八)(下)
ARM架构与编程(基于I.MX6ULL): 代码重定位(八)
288 0
|
C语言 内存技术
ARM架构与编程(基于I.MX6ULL): 代码重定位(八)(上)
ARM架构与编程(基于I.MX6ULL): 代码重定位(八)
336 0
|
NoSQL 网络协议 Linux
【GDB调试】Linux Core Dump分析经典案例之一
这次我们一起来看一下在GDB调试中属于比较典型的案例,因此也借这篇文章向大家阐述个人在分析Core Dump时的一些思路。
5216 0
|
Linux 开发者 SoC
宋牧春: Linux设备树文件结构与解析深度分析(2) 【转】
转自:https://mp.weixin.qq.com/s/WPZSElF3OQPMGqdoldm07A             作者简介   宋牧春,linux内核爱好者,喜欢阅读各种开源代码(uboot、linux、ucos、rt-thread等),对于优秀的代码框架及其痴迷。
1633 0