当前位置: 首页> 文旅> 艺术 > 营销推广的渠道方式_公司页面设计图片_seo网站推广推荐_seo优化网站推广全域营销获客公司

营销推广的渠道方式_公司页面设计图片_seo网站推广推荐_seo优化网站推广全域营销获客公司

时间:2025/7/10 16:54:28来源:https://blog.csdn.net/weixin_45030965/article/details/146496491 浏览次数:0次
营销推广的渠道方式_公司页面设计图片_seo网站推广推荐_seo优化网站推广全域营销获客公司

文章目录

  • 前言
  • 一、获取符号信息
    • 1.1 相关结构体
    • 1.2 代码示例1
    • 1.3 代码示例2
  • 二、Elf64_Shdr的字段sh_link
    • 2.1 简介
    • 2.2 代码示例 - sh_link用于符号表
    • 2.3 代码示例 - sh_link用于重定位节
  • 三、获取导出符号

前言

关于ELF文件的信息请参考:Linux C语言读取elf文件的代码段,重定位段

一、获取符号信息

1.1 相关结构体

节头表:

typedef struct
{Elf64_Word	sh_name;		/* Section name (string tbl index) */Elf64_Word	sh_type;		/* Section type */Elf64_Xword	sh_flags;		/* Section flags */Elf64_Addr	sh_addr;		/* Section virtual addr at execution */Elf64_Off	sh_offset;		/* Section file offset */Elf64_Xword	sh_size;		/* Section size in bytes */Elf64_Word	sh_link;		/* Link to another section */Elf64_Word	sh_info;		/* Additional section information */Elf64_Xword	sh_addralign;		/* Section alignment */Elf64_Xword	sh_entsize;		/* Entry size if section holds table */
} Elf64_Shdr;

符号表:

typedef struct
{Elf64_Word	st_name;		/* Symbol name (string tbl index) */unsigned char	st_info;		/* Symbol type and binding */unsigned char st_other;		/* Symbol visibility */Elf64_Section	st_shndx;		/* Section index */Elf64_Addr	st_value;		/* Symbol value */Elf64_Xword	st_size;		/* Symbol size */
} Elf64_Sym;

1.2 代码示例1

下面是获取符号值的相关代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <elf.h>// 检查ELF头有效性
int check_elf_header(Elf64_Ehdr *ehdr) {if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {fprintf(stderr, "Not an ELF file\n");return 0;}if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {fprintf(stderr, "Not a 64-bit ELF file\n");return 0;}return 1;
}// 获取符号绑定类型字符串
const char* get_symbol_bind(Elf64_Sym *sym) {switch(ELF64_ST_BIND(sym->st_info)) {case STB_LOCAL:  return "LOCAL";case STB_GLOBAL: return "GLOBAL";case STB_WEAK:   return "WEAK";default:        return "UNKNOWN";}
}// 获取符号类型字符串
const char* get_symbol_type(Elf64_Sym *sym) {switch(ELF64_ST_TYPE(sym->st_info)) {case STT_NOTYPE:  return "NOTYPE";case STT_OBJECT: return "OBJECT";case STT_FUNC:   return "FUNC";case STT_SECTION: return "SECTION";case STT_FILE:   return "FILE";case STT_COMMON: return "COMMON";case STT_TLS:    return "TLS";default:         return "UNKNOWN";}
}// 获取符号可见性字符串
const char* get_symbol_visibility(Elf64_Sym *sym) {switch(ELF64_ST_VISIBILITY(sym->st_other)) {case STV_DEFAULT:   return "DEFAULT";case STV_INTERNAL: return "INTERNAL";case STV_HIDDEN:   return "HIDDEN";case STV_PROTECTED: return "PROTECTED";default:           return "UNKNOWN";}
}// 处理符号表
void process_symbol_table(Elf64_Shdr *shdr, Elf64_Shdr *symtab_shdr, Elf64_Shdr *strtab_shdr, void *file_data) {Elf64_Sym *syms = (Elf64_Sym *)(file_data + symtab_shdr->sh_offset);int num_syms = symtab_shdr->sh_size / sizeof(Elf64_Sym);const char *strtab = (const char *)(file_data + strtab_shdr->sh_offset);printf("Found %d symbols in symbol table\n", num_syms);printf("%-30s %-8s %-8s %-8s %-12s %-8s %s\n", "Name", "Value", "Size", "Bind", "Type", "Vis", "Section");for (int i = 0; i < num_syms; i++) {Elf64_Sym *sym = &syms[i];const char *name = "(unnamed)";if (sym->st_name != 0) {name = strtab + sym->st_name;}printf("%-30s 0x%06lx %-8lu %-8s %-8s %-8s %d\n",name,sym->st_value,sym->st_size,get_symbol_bind(sym),get_symbol_type(sym),get_symbol_visibility(sym),sym->st_shndx);}
}int main(int argc, char *argv[]) {if (argc < 2) {fprintf(stderr, "Usage: %s <kernel_module.ko>\n", argv[0]);return 1;}// 打开并映射.ko文件int fd = open(argv[1], O_RDONLY);if (fd == -1) {perror("open");return 1;}struct stat st;if (fstat(fd, &st) == -1) {perror("fstat");close(fd);return 1;}void *file_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);if (file_data == MAP_FAILED) {perror("mmap");close(fd);return 1;}// 检查ELF头Elf64_Ehdr *ehdr = (Elf64_Ehdr *)file_data;if (!check_elf_header(ehdr)) {munmap(file_data, st.st_size);close(fd);return 1;}// 获取节头表和节字符串表Elf64_Shdr *shdrs = (Elf64_Shdr *)(file_data + ehdr->e_shoff);char *shstrtab = (char *)(file_data + shdrs[ehdr->e_shstrndx].sh_offset);// 查找符号表和字符串表Elf64_Shdr *symtab_shdr = NULL, *strtab_shdr = NULL;for (int i = 0; i < ehdr->e_shnum; i++) {const char *name = shstrtab + shdrs[i].sh_name;if (!symtab_shdr && (strcmp(name, ".symtab") == 0)) {symtab_shdr = &shdrs[i];} else if (!strtab_shdr && (strcmp(name, ".strtab") == 0)) {strtab_shdr = &shdrs[i];}}if (!symtab_shdr || !strtab_shdr) {fprintf(stderr, "Symbol table or string table not found\n");munmap(file_data, st.st_size);close(fd);return 1;}printf("Symbol table found at section %ld\n", symtab_shdr - shdrs);printf("String table found at section %ld\n", strtab_shdr - shdrs);// 处理符号表process_symbol_table(shdrs, symtab_shdr, strtab_shdr, file_data);// 清理munmap(file_data, st.st_size);close(fd);return 0;
}

对于符号的类型:

#define STB_LOCAL	0		/* Local symbol */
#define STB_GLOBAL	1		/* Global symbol */
#define STB_WEAK	2		/* Weak symbol */

STB_GLOBAL 是全局符号,是需要重定位的符号。指向全局符号的未定义引用,将在重定位期间确定相关符号的位置。

1.3 代码示例2

要获取符号在 .ko 文件 中的实际物理偏移量(即该符号在文件中的具体位置),计算公式如下:
符号在文件中的物理偏移量 =

Symbol File Offset = sh_offset(所属节的物理偏移) + st_value(符号在节内的偏移)
Symbol File Offset = Elf64_Shdr->sh_offset + Elf64_Sym->st_value

st_value是符号相对于其所属节起始位置的偏移量。
sh_offset(节头表字段)表示该节在ELF文件中的物理偏移量(即从文件开头到节数据的字节偏移)。用于定位节数据在文件中的实际存储位置。

具体实现步骤
(1)找到符号所属的节
符号的 st_shndx 字段表示它在哪个节(Elf64_Shdr 数组的索引)。
如果 st_shndx == SHN_UNDEF,表示该符号未定义(如外部引用的函数)。

(2)获取该节的 sh_offset
从节头表(Elf64_Shdr)中获取该节的 sh_offset,即该节在文件中的起始偏移。

(3)计算符号的文件偏移
File Offset=sh_offset+st_value

代码示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <elf.h>// 获取符号类型名称
const char* get_symbol_type(Elf64_Sym *sym) {switch (ELF64_ST_TYPE(sym->st_info)) {case STT_NOTYPE:  return "NOTYPE";case STT_OBJECT:  return "OBJECT";case STT_FUNC:    return "FUNC";case STT_SECTION: return "SECTION";case STT_FILE:    return "FILE";default:          return "UNKNOWN";}
}// 打印符号的文件偏移
void print_symbol_file_offset(Elf64_Shdr *shdrs, Elf64_Sym *sym, const char *name, const char *shstrtab) {if (sym->st_shndx == SHN_UNDEF) {printf("Symbol: %-30s (Undefined, no file offset)\n", name);return;}// 获取所属节的名称const char *section_name = shstrtab + shdrs[sym->st_shndx].sh_name;// 计算符号在文件中的物理偏移// 指针也是数组,sym->st_shndx是该符号坐在节数组的序号,shdrs[sym->st_shndx]找到该节结构体的起始地址Elf64_Off file_offset = shdrs[sym->st_shndx].sh_offset + sym->st_value;printf("Symbol: %-30s Type: %-8s Section: %-10s File Offset: 0x%lx\n",name, get_symbol_type(sym), section_name, file_offset);
}int main(int argc, char *argv[]) {if (argc < 2) {fprintf(stderr, "Usage: %s <kernel_module.ko>\n", argv[0]);return 1;}// 打开并映射 .ko 文件int fd = open(argv[1], O_RDONLY);if (fd == -1) {perror("open");return 1;}struct stat st;if (fstat(fd, &st) == -1) {perror("fstat");close(fd);return 1;}void *file_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);if (file_data == MAP_FAILED) {perror("mmap");close(fd);return 1;}// 检查 ELF 头Elf64_Ehdr *ehdr = (Elf64_Ehdr *)file_data;if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0 || ehdr->e_ident[EI_CLASS] != ELFCLASS64) {fprintf(stderr, "Not a valid 64-bit ELF file\n");munmap(file_data, st.st_size);close(fd);return 1;}// 获取节头表和节字符串表Elf64_Shdr *shdrs = (Elf64_Shdr *)(file_data + ehdr->e_shoff);char *shstrtab = (char *)(file_data + shdrs[ehdr->e_shstrndx].sh_offset);// 查找符号表(.symtab)和字符串表(.strtab)Elf64_Shdr *symtab_shdr = NULL, *strtab_shdr = NULL;for (int i = 0; i < ehdr->e_shnum; i++) {const char *name = shstrtab + shdrs[i].sh_name;if (!symtab_shdr && strcmp(name, ".symtab") == 0) {symtab_shdr = &shdrs[i];} else if (!strtab_shdr && strcmp(name, ".strtab") == 0) {strtab_shdr = &shdrs[i];}}if (!symtab_shdr || !strtab_shdr) {fprintf(stderr, "Symbol table or string table not found\n");munmap(file_data, st.st_size);close(fd);return 1;}// 遍历符号表Elf64_Sym *syms = (Elf64_Sym *)(file_data + symtab_shdr->sh_offset);int num_syms = symtab_shdr->sh_size / sizeof(Elf64_Sym);const char *sym_names = (const char *)(file_data + strtab_shdr->sh_offset);printf("Symbols in %s:\n", argv[1]);for (int i = 0; i < num_syms; i++) {Elf64_Sym *sym = &syms[i];const char *name = sym_names + sym->st_name;print_symbol_file_offset(shdrs, sym, name, shstrtab);}munmap(file_data, st.st_size);close(fd);return 0;
}
    // 计算符号在文件中的物理偏移// 指针也是数组,sym->st_shndx是该符号坐在节数组的序号,shdrs[sym->st_shndx]找到该节结构体的起始地址Elf64_Off file_offset = shdrs[sym->st_shndx].sh_offset + sym->st_value;

节头表通过数组实现的,每个数组项包含一节的信息。获取对应数组项:

shdrs[sym->st_shndx]

比如符号perf_trace_xfs_attr_list_class,计算出:

Symbol: perf_trace_xfs_attr_list_class Type: FUNC     Section: .text      File Offset: 0xb400

那么我们通过readelf命令查看:

$ readelf -s xfs.koSymbol table '.symtab' contains 8605 entries:Num:    Value          Size Type    Bind   Vis      Ndx Name......24: 000000000000b360   294 FUNC    LOCAL  DEFAULT    3 perf_trace_xfs_attr_list_class 
$ readelf -S xfs.ko | more
There are 66 section headers, starting at offset 0x33f8c0:Section Headers:[Nr] Name              Type             Address           OffsetSize              EntSize          Flags  Link  Info  Align......[ 3] .text             PROGBITS         0000000000000000  000000a000000000000c1b6c  0000000000000000  AX       0     0     16
0xa0 + 0xb360 = 0xb400

二、Elf64_Shdr的字段sh_link

2.1 简介

在ELF (Executable and Linkable Format) 文件格式中,Elf64_Shdr(64位ELF节头结构体)的sh_link字段是一个非常重要的字段,它的具体作用取决于当前节的类型。以下是详细解释:

sh_link 是一个索引值,指向与该节相关联的其他节。具体含义由当前节的类型(sh_type)决定:
|

节类型 (sh_type)sh_link 的含义
SHT_SYMTAB /SHT_DYNSYM指向关联的字符串表(通常是 .strtab 或 .dynstr 节),存储符号名称。
SHT_REL / SHT_RELA指向符号表(.symtab 或 .dynsym 节),用于解析重定位项中的符号索引。
SHT_HASH指向符号表(.dynsym 节),用于动态链接的哈希表。
SHT_DYNAMIC指向字符串表(.dynstr 节),存储动态链接所需的符号名称。
SHT_GROUP指向符号表(.symtab 节),标识节组的签名符号。
其他类型通常为 0(SHN_UNDEF),表示无关联节。

关键用途示例:
(1)符号表 (SHT_SYMTAB)
sh_link 指向字符串表(如 .strtab),因为符号名称存储在字符串表中。
例如,以下代码通过 sh_link 找到符号名称:

Elf64_Shdr *symtab = &shdrs[symtab_idx];
const char *strtab = (char *)file_data + shdrs[symtab->sh_link].sh_offset;
const char *sym_name = strtab + sym->st_name; // 获取符号名

(2)重定位节 (SHT_REL/SHT_RELA)
sh_link 指向符号表(如 .symtab),用于解析重定位项中的符号索引。
例如:

Elf64_Shdr *reloc_sec = &shdrs[reloc_idx];
Elf64_Sym *symtab = (Elf64_Sym *)(file_data + shdrs[reloc_sec->sh_link].sh_offset);
Elf64_Sym *sym = &symtab[ELF64_R_SYM(rel->r_info)]; // 获取关联的符号

ELF 文件通过 sh_link 实现节之间的关联,避免将数据直接嵌入节中,从而保持灵活性。例如:
符号表无需直接存储字符串,而是通过 sh_link 引用独立的字符串表。
重定位节通过 sh_link 找到符号表,而不是硬编码位置。

实际代码中的使用
在解析ELF文件时,通常需要结合 sh_type 和 sh_link 来正确解析数据。例如:

Elf64_Shdr *shdr = &shdrs[i];
if (shdr->sh_type == SHT_SYMTAB) {// sh_link 指向字符串表const char *strtab = (char *)file_data + shdrs[shdr->sh_link].sh_offset;// 处理符号表...
} else if (shdr->sh_type == SHT_RELA) {// sh_link 指向符号表Elf64_Sym *symtab = (Elf64_Sym *)(file_data + shdrs[shdr->sh_link].sh_offset);// 处理重定位...
}

sh_link 是 节头中的关联字段,指向当前节依赖的其他节。
具体含义由 sh_type 决定,常见于符号表、重定位节和动态节。

2.2 代码示例 - sh_link用于符号表

关键用途示例:
符号表 (SHT_SYMTAB)
sh_link 指向字符串表(如 .strtab),因为符号名称存储在字符串表中。
例如,以下代码通过 sh_link 找到符号名称:

Elf64_Shdr *symtab = &shdrs[symtab_idx];
const char *strtab = (char *)file_data + shdrs[symtab->sh_link].sh_offset;
const char *sym_name = strtab + sym->st_name; // 获取符号名
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <elf.h>// 获取符号绑定类型
const char* get_symbol_bind(Elf64_Sym *sym) {switch (ELF64_ST_BIND(sym->st_info)) {case STB_LOCAL:  return "LOCAL";case STB_GLOBAL: return "GLOBAL";case STB_WEAK:   return "WEAK";default:         return "UNKNOWN";}
}// 获取符号类型
const char* get_symbol_type(Elf64_Sym *sym) {switch (ELF64_ST_TYPE(sym->st_info)) {case STT_NOTYPE:  return "NOTYPE";case STT_OBJECT:  return "OBJECT";case STT_FUNC:    return "FUNC";case STT_SECTION: return "SECTION";case STT_FILE:    return "FILE";default:         return "UNKNOWN";}
}// 打印符号信息
void print_symbol_info(Elf64_Sym *sym, const char *name, const char *shstrtab, Elf64_Shdr *shdrs) {printf("Symbol: %-30s ", name);printf("Type: %-8s ", get_symbol_type(sym));printf("Bind: %-8s ", get_symbol_bind(sym));printf("Value: 0x%lx ", sym->st_value);printf("Size: %-6lu ", sym->st_size);// 打印所属节名称(如果有)if (sym->st_shndx != SHN_UNDEF) {const char *section_name = shstrtab + shdrs[sym->st_shndx].sh_name;printf("Section: %-10s", section_name);} else {printf("Section: UNDEF     ");}// 计算文件偏移(仅对已定义符号有效)if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {Elf64_Off file_offset = shdrs[sym->st_shndx].sh_offset + sym->st_value;printf("File Offset: 0x%lx", file_offset);}printf("\n");
}int main(int argc, char *argv[]) {if (argc < 2) {fprintf(stderr, "Usage: %s <kernel_module.ko>\n", argv[0]);return 1;}// 打开并映射 .ko 文件int fd = open(argv[1], O_RDONLY);if (fd == -1) {perror("open");return 1;}struct stat st;if (fstat(fd, &st) == -1) {perror("fstat");close(fd);return 1;}void *file_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);if (file_data == MAP_FAILED) {perror("mmap");close(fd);return 1;}// 检查 ELF 头Elf64_Ehdr *ehdr = (Elf64_Ehdr *)file_data;if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0 || ehdr->e_ident[EI_CLASS] != ELFCLASS64) {fprintf(stderr, "Not a valid 64-bit ELF file\n");munmap(file_data, st.st_size);close(fd);return 1;}// 获取节头表和节字符串表Elf64_Shdr *shdrs = (Elf64_Shdr *)(file_data + ehdr->e_shoff);char *shstrtab = (char *)(file_data + shdrs[ehdr->e_shstrndx].sh_offset);// 查找符号表(.symtab)和字符串表(.strtab)Elf64_Shdr *symtab_shdr = NULL;for (int i = 0; i < ehdr->e_shnum; i++) {const char *name = shstrtab + shdrs[i].sh_name;if (strcmp(name, ".symtab") == 0) {symtab_shdr = &shdrs[i];break;}}if (!symtab_shdr) {fprintf(stderr, "Symbol table (.symtab) not found\n");munmap(file_data, st.st_size);close(fd);return 1;}// 通过 sh_link 获取字符串表Elf64_Shdr *strtab_shdr = &shdrs[symtab_shdr->sh_link];const char *strtab = (const char *)(file_data + strtab_shdr->sh_offset);// 遍历符号表Elf64_Sym *syms = (Elf64_Sym *)(file_data + symtab_shdr->sh_offset);int num_syms = symtab_shdr->sh_size / sizeof(Elf64_Sym);printf("Symbols in %s:\n", argv[1]);for (int i = 0; i < num_syms; i++) {Elf64_Sym *sym = &syms[i];const char *name = strtab + sym->st_name;print_symbol_info(sym, name, shstrtab, shdrs);}munmap(file_data, st.st_size);close(fd);return 0;
}
    // 通过 sh_link 获取字符串表Elf64_Shdr *strtab_shdr = &shdrs[symtab_shdr->sh_link];const char *strtab = (const char *)(file_data + strtab_shdr->sh_offset);

2.3 代码示例 - sh_link用于重定位节

重定位节 (SHT_REL/SHT_RELA)
sh_link 指向符号表(如 .symtab),用于解析重定位项中的符号索引。
例如:

Elf64_Shdr *reloc_sec = &shdrs[reloc_idx];
Elf64_Sym *symtab = (Elf64_Sym *)(file_data + shdrs[reloc_sec->sh_link].sh_offset);
Elf64_Sym *sym = &symtab[ELF64_R_SYM(rel->r_info)]; // 获取关联的符号```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <elf.h>// 获取重定位类型名称(x86_64架构示例)
const char* get_reloc_type(Elf64_Word type) {switch(type) {case R_X86_64_NONE:      return "R_X86_64_NONE";case R_X86_64_64:        return "R_X86_64_64";case R_X86_64_PC32:      return "R_X86_64_PC32";case R_X86_64_GOT32:     return "R_X86_64_GOT32";case R_X86_64_PLT32:     return "R_X86_64_PLT32";case R_X86_64_RELATIVE:  return "R_X86_64_RELATIVE";case R_X86_64_GOTPCREL:  return "R_X86_64_GOTPCREL";case R_X86_64_32:        return "R_X86_64_32";case R_X86_64_32S:       return "R_X86_64_32S";default:                 return "UNKNOWN";}
}// 解析重定位节
void process_relocation_section(Elf64_Shdr *reloc_shdr, Elf64_Shdr *symtab_shdr,Elf64_Shdr *strtab_shdr,void *file_data,const char *shstrtab) {// 获取重定位节的名称(如.rela.text)const char *reloc_name = shstrtab + reloc_shdr->sh_name;printf("\nProcessing relocation section: %s\n", reloc_name);// 确定重定位条目是REL还是RELAint is_rela = (reloc_shdr->sh_type == SHT_RELA);size_t entry_size = is_rela ? sizeof(Elf64_Rela) : sizeof(Elf64_Rel);int num_entries = reloc_shdr->sh_size / entry_size;// 获取重定位表数据void *reloc_data = file_data + reloc_shdr->sh_offset;// 通过sh_link获取符号表Elf64_Sym *symtab = (Elf64_Sym *)(file_data + symtab_shdr->sh_offset);const char *strtab = (const char *)(file_data + strtab_shdr->sh_offset);// 遍历所有重定位项for (int i = 0; i < num_entries; i++) {Elf64_Addr r_offset;Elf64_Xword r_info;Elf64_Sxword r_addend = 0;if (is_rela) {Elf64_Rela *rela = (Elf64_Rela *)reloc_data + i;r_offset = rela->r_offset;r_info = rela->r_info;r_addend = rela->r_addend;} else {Elf64_Rel *rel = (Elf64_Rel *)reloc_data + i;r_offset = rel->r_offset;r_info = rel->r_info;}// 从r_info中提取符号索引和重定位类型Elf64_Word sym_index = ELF64_R_SYM(r_info);Elf64_Word reloc_type = ELF64_R_TYPE(r_info);// 获取符号信息Elf64_Sym *sym = &symtab[sym_index];const char *sym_name = "(unknown)";if (sym->st_name != 0) {sym_name = strtab + sym->st_name;}// 打印重定位项详情printf("  Relocation %d:\n", i);printf("    r_offset: 0x%lx (address to modify)\n", r_offset);printf("    r_info: 0x%lx (sym_index=%u, type=%s)\n", r_info, sym_index, get_reloc_type(reloc_type));if (is_rela) {printf("    r_addend: %ld\n", r_addend);}printf("    Symbol: %s (value=0x%lx, size=%lu, bind=%s, type=%s)\n",sym_name, sym->st_value, sym->st_size,(ELF64_ST_BIND(sym->st_info) == STB_GLOBAL) ? "GLOBAL" : "LOCAL",(ELF64_ST_TYPE(sym->st_info) == STT_FUNC) ? "FUNC" : "OBJECT");}
}int main(int argc, char *argv[]) {if (argc < 2) {fprintf(stderr, "Usage: %s <kernel_module.ko>\n", argv[0]);return 1;}// 打开并映射ELF文件int fd = open(argv[1], O_RDONLY);if (fd == -1) {perror("open");return 1;}struct stat st;if (fstat(fd, &st) == -1) {perror("fstat");close(fd);return 1;}void *file_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);if (file_data == MAP_FAILED) {perror("mmap");close(fd);return 1;}// 检查ELF头Elf64_Ehdr *ehdr = (Elf64_Ehdr *)file_data;if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0 || ehdr->e_ident[EI_CLASS] != ELFCLASS64) {fprintf(stderr, "Not a valid 64-bit ELF file\n");munmap(file_data, st.st_size);close(fd);return 1;}// 获取节头表和节字符串表Elf64_Shdr *shdrs = (Elf64_Shdr *)(file_data + ehdr->e_shoff);char *shstrtab = (char *)(file_data + shdrs[ehdr->e_shstrndx].sh_offset);// 查找符号表和字符串表(用于解析符号名)Elf64_Shdr *symtab_shdr = NULL, *strtab_shdr = NULL;for (int i = 0; i < ehdr->e_shnum; i++) {const char *name = shstrtab + shdrs[i].sh_name;if (!symtab_shdr && strcmp(name, ".symtab") == 0) {symtab_shdr = &shdrs[i];} else if (!strtab_shdr && strcmp(name, ".strtab") == 0) {strtab_shdr = &shdrs[i];}}if (!symtab_shdr || !strtab_shdr) {fprintf(stderr, "Symbol table or string table not found\n");munmap(file_data, st.st_size);close(fd);return 1;}// 遍历所有节,查找重定位节(SHT_REL/SHT_RELA)for (int i = 0; i < ehdr->e_shnum; i++) {if (shdrs[i].sh_type == SHT_REL || shdrs[i].sh_type == SHT_RELA) {// 重定位节的sh_link指向符号表Elf64_Shdr *linked_symtab = &shdrs[shdrs[i].sh_link];process_relocation_section(&shdrs[i], linked_symtab, strtab_shdr, file_data, shstrtab);}}munmap(file_data, st.st_size);close(fd);return 0;
}
    // 重定位节的sh_link指向符号表Elf64_Shdr *linked_symtab = &shdrs[shdrs[i].sh_link];process_relocation_section(&shdrs[i], linked_symtab, strtab_shdr, file_data, shstrtab);// 通过sh_link获取符号表Elf64_Sym *symtab = (Elf64_Sym *)(file_data + symtab_shdr->sh_offset);

三、获取导出符号

关于导出符号请参考:Linux EXPORT_SYMBOL宏详解
对于3.10.0:

// linux/v3.10/source/include/linux/export.hstruct kernel_symbol
{unsigned long value;const char *name;
};

对于5.15.0

// linux/v5.15/source/include/linux/export.h#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
#include <linux/compiler.h>
/** Emit the ksymtab entry as a pair of relative references: this reduces* the size by half on 64-bit architectures, and eliminates the need for* absolute relocations that require runtime processing on relocatable* kernels.*/
#define __KSYMTAB_ENTRY(sym, sec)					\__ADDRESSABLE(sym)						\asm("	.section \"___ksymtab" sec "+" #sym "\", \"a\"	\n"	\"	.balign	4					\n"	\"__ksymtab_" #sym ":				\n"	\"	.long	" #sym "- .				\n"	\"	.long	__kstrtab_" #sym "- .			\n"	\"	.long	__kstrtabns_" #sym "- .			\n"	\"	.previous					\n")struct kernel_symbol {int value_offset;int name_offset;int namespace_offset;
};

这个struct kernel_symbol结构体在高版本有改动。

我们通过其他方式来获取导出的函数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <elf.h>// 检查ELF头有效性
int check_elf_header(Elf64_Ehdr *ehdr) {if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {fprintf(stderr, "Not an ELF file\n");return 0;}if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {fprintf(stderr, "Not a 64-bit ELF file\n");return 0;}return 1;
}// 获取符号类型名称
const char* get_symbol_type(Elf64_Sym *sym) {switch(ELF64_ST_TYPE(sym->st_info)) {case STT_NOTYPE:  return "NOTYPE";case STT_OBJECT:  return "OBJECT";case STT_FUNC:    return "FUNC";case STT_SECTION: return "SECTION";case STT_FILE:    return "FILE";default:         return "UNKNOWN";}
}// 获取符号绑定类型
const char* get_symbol_bind(Elf64_Sym *sym) {switch(ELF64_ST_BIND(sym->st_info)) {case STB_LOCAL:  return "LOCAL";case STB_GLOBAL: return "GLOBAL";case STB_WEAK:   return "WEAK";default:         return "UNKNOWN";}
}int main(int argc, char *argv[]) {if (argc < 2) {fprintf(stderr, "Usage: %s <kernel_module.ko>\n", argv[0]);return 1;}// 打开并映射ELF文件int fd = open(argv[1], O_RDONLY);if (fd == -1) {perror("open");return 1;}struct stat st;if (fstat(fd, &st) == -1) {perror("fstat");close(fd);return 1;}void *file_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);if (file_data == MAP_FAILED) {perror("mmap");close(fd);return 1;}// 检查ELF头Elf64_Ehdr *ehdr = (Elf64_Ehdr *)file_data;if (!check_elf_header(ehdr)) {munmap(file_data, st.st_size);close(fd);return 1;}// 获取节头表和节字符串表Elf64_Shdr *shdrs = (Elf64_Shdr *)(file_data + ehdr->e_shoff);char *shstrtab = (char *)(file_data + shdrs[ehdr->e_shstrndx].sh_offset);// 查找.symtab和.strtab节Elf64_Shdr *symtab_shdr = NULL, *strtab_shdr = NULL;for (int i = 0; i < ehdr->e_shnum; i++) {const char *name = shstrtab + shdrs[i].sh_name;if (strcmp(name, ".symtab") == 0) {symtab_shdr = &shdrs[i];} else if (strcmp(name, ".strtab") == 0) {strtab_shdr = &shdrs[i];}}if (!symtab_shdr || !strtab_shdr) {fprintf(stderr, ".symtab or .strtab section not found\n");munmap(file_data, st.st_size);close(fd);return 1;}// 获取符号表和字符串表数据Elf64_Sym *symtab = (Elf64_Sym *)(file_data + symtab_shdr->sh_offset);int num_syms = symtab_shdr->sh_size / sizeof(Elf64_Sym);const char *strtab = (const char *)(file_data + strtab_shdr->sh_offset);printf("Kernel exported symbols (__ksymtab_*):\n");printf("%-40s %-8s %-8s %-12s %-10s %s\n", "Name", "Type", "Bind", "Value", "Size", "Section");// 遍历所有符号,查找以"__ksymtab_"开头的for (int i = 0; i < num_syms; i++) {Elf64_Sym *sym = &symtab[i];const char *name = strtab + sym->st_name;// 检查符号名是否以"__ksymtab_"开头if (strncmp(name, "__ksymtab_", 10) == 0) {const char *exported_name = name + 10; // 去掉"__ksymtab_"前缀const char *section_name = (sym->st_shndx != SHN_UNDEF) ? shstrtab + shdrs[sym->st_shndx].sh_name : "UNDEF";printf("%-40s %-8s %-8s 0x%08lx %-10lu %s\n",exported_name,get_symbol_type(sym),get_symbol_bind(sym),sym->st_value,sym->st_size,section_name);}}munmap(file_data, st.st_size);close(fd);return 0;
}

结果显示:

$ ./a.out snd-sof-intel-hda-common.ko
Kernel exported symbols (__ksymtab_*):
Name                                     Type     Bind     Value        Size       Section
hda_pci_intel_probe                      NOTYPE   LOCAL    0x00000030 0          __ksymtab
sof_apl_ops                              NOTYPE   LOCAL    0x00000054 0          __ksymtab
apl_chip_info                            NOTYPE   LOCAL    0x0000000c 0          __ksymtab
sof_cnl_ops                              NOTYPE   LOCAL    0x00000060 0          __ksymtab
cnl_chip_info                            NOTYPE   LOCAL    0x00000018 0          __ksymtab
jsl_chip_info                            NOTYPE   LOCAL    0x00000048 0          __ksymtab
sof_tgl_ops                              NOTYPE   LOCAL    0x00000078 0          __ksymtab
tgl_chip_info                            NOTYPE   LOCAL    0x00000084 0          __ksymtab
tglh_chip_info                           NOTYPE   LOCAL    0x00000090 0          __ksymtab
ehl_chip_info                            NOTYPE   LOCAL    0x00000024 0          __ksymtab
adls_chip_info                           NOTYPE   LOCAL    0x00000000 0          __ksymtab
sof_icl_ops                              NOTYPE   LOCAL    0x0000006c 0          __ksymtab
icl_chip_info                            NOTYPE   LOCAL    0x0000003c 0          __ksymtab

使用readelf查看:

$ nm snd-sof-intel-hda-common.ko | grep __ksymtab
0000000000000000 r __ksymtab_adls_chip_info
000000000000000c r __ksymtab_apl_chip_info
0000000000000018 r __ksymtab_cnl_chip_info
0000000000000024 r __ksymtab_ehl_chip_info
0000000000000030 r __ksymtab_hda_pci_intel_probe
000000000000003c r __ksymtab_icl_chip_info
0000000000000048 r __ksymtab_jsl_chip_info
0000000000000054 r __ksymtab_sof_apl_ops
0000000000000060 r __ksymtab_sof_cnl_ops
000000000000006c r __ksymtab_sof_icl_ops
0000000000000078 r __ksymtab_sof_tgl_ops
0000000000000084 r __ksymtab_tgl_chip_info
0000000000000090 r __ksymtab_tglh_chip_info
关键字:营销推广的渠道方式_公司页面设计图片_seo网站推广推荐_seo优化网站推广全域营销获客公司

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: