Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C Elf Symtab解析空指针_C_Assembly_Elf - Fatal编程技术网

C Elf Symtab解析空指针

C Elf Symtab解析空指针,c,assembly,elf,C,Assembly,Elf,我讨厌让别人帮我调试代码,但我真的很坚持。我有一个简单的代码片段,用于遍历symtab中的符号,然后将它们打印到控制台。显然,在对printf和strcmp的调用中,我有一个空指针(导致segfault),但我似乎不知道为什么。 以下是代码片段: #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <elf.h> #

我讨厌让别人帮我调试代码,但我真的很坚持。我有一个简单的代码片段,用于遍历symtab中的符号,然后将它们打印到控制台。显然,在对
printf
strcmp
的调用中,我有一个空指针(导致segfault),但我似乎不知道为什么。 以下是代码片段:

    #include <stdio.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <elf.h>
    #include <fcntl.h>


    #ifdef DEBUG
    #define PRINTDEBUG(x) printf x //variable number of arguments
    #else
    #define PRINTDEBUG(x) do{} while(0)
    #endif

    uint32_t main(int argc, char** argv){
        char* filename = argv[1];
        char* sym_name = argv[2];
        int fd = open(filename, O_RDONLY);
        struct stat st;
        stat(fd, &st);


    char mem[st.st_size];
        read(fd, mem, st.st_size);

        Elf32_Ehdr* ehdr;
        Elf32_Shdr* shdr; //generic entry for enumerating sections
        Elf32_Shdr strtab; //holds string in symtab
        Elf32_Shdr symtab;
        char* sh_strtab; //hold sections names
        Elf32_Sym* sym;


        ehdr = (Elf32_Ehdr *)mem;
        shdr = (Elf32_Shdr* )(mem + ehdr->e_shoff);
        PRINTDEBUG(("number of section headers: %d\n", ehdr->e_shnum)); //need double brackets for variable #of arguments


        sh_strtab = (char *)(mem + (shdr[ehdr->e_shstrndx].sh_offset)); 

        //find address of symtab and strtab 
        for(int i = 0; i < ehdr->e_shnum; i++){
            if(shdr[i].sh_size){

            printf("%s\n", &sh_strtab[shdr[i].sh_name]);

            if(strcmp(&sh_strtab[shdr[i].sh_name], ".strtab") == 0)
                strtab = shdr[i];
            if(strcmp(&sh_strtab[shdr[i].sh_name], ".symtab") == 0)
                symtab = shdr[i];           

            }
        }
    PRINTDEBUG(("symtab offset %x\n", symtab.sh_offset));
    PRINTDEBUG(("strtab offset %x\n", strtab.sh_offset));

    char* symtab_str = (char *)(mem + strtab.sh_offset);
    sym = (Elf32_Sym* )(mem + symtab.sh_offset);

    printf("Symbol names: \n");
    for(int i = 0;  i < (symtab.sh_size / symtab.sh_entsize); i++, sym++){
        printf("%x\n",&symtab_str[sym->st_name]);
        if(strcmp(&symtab_str[sym->st_name], sym_name) ==0) 
            printf("not crahsed\n");

        //TODO: resolve reloc'd syms
    }
}
我已经按照我的初衷工作了。然而,我不确定SEGFULT的原因,正如EmployeedRussian指出的,我最初的答案不是问题的根本原因。我真的很想弄清这个谜团的真相,希望能从中有所收获

正如您所看到的,eax中存储的地址指向.strtab中的第一个字符串,那么为什么在将其传递给strcmp时会得到一个空指针呢

您显示的代码片段似乎是正确的,如果调用
strcmp
eax
0xffd6a030
,则根据定义它不是
NULL


您(没有证据支持)断言它为
NULL
似乎是错误的(换句话说,您可能错误地解释了某些内容,并且您没有显示这些内容)。

根据ELF规范的本节:

字符串表部分包含以null结尾的字符序列, 通常称为字符串。对象使用这些字符串来表示 符号和节名称。可以引用字符串作为索引 字符串表部分。第一个字节(索引为零)是 定义为保存空字符


这意味着symtab_str[0]指向一个空字符,当在strcmp中取消引用该字符时,会导致Segfault。在执行strcmp之前修改代码以检查空字符串修复了该问题

为什么强制转换
sym=(Elf32_sym*)(mem+symtab.sh_offset)?我会使用
-g
进行符号编译,并在进入汇编程序级别之前检查C代码。大量代码缺失,请共享一个最小、完整且可验证的示例。在缺失的代码之上,您有误导性的注释-如果
symtab是指向.symtab
的(Elf32_Shdr)指针,如何使用
而不是
->
访问它?我已经重新发布了完整的代码片段。参数char*file只是指向读取到内存中的Elf文件的指针。我运行了strace并得到以下输出:write(1,“Symbol names:\n”,15Symbol names:)=15 write(1,“\n”,1)=1---SIGSEGV{si_signo=SIGSEGV,si_code=SEGV_MAPERR,si_addr=0}---++被SIGSEGV(内核转储)杀死+++分段错误(内核转储)抱歉,我不确定如何打印格式化的输出,但正如您所看到的,signal struct的si_addr字段是0,我用它表示空指针dereference@JohnPeng您将从某处获得
SIGSEGV
NULL
指针解引用,但不是从您显示的代码
strace
确实是错误的调试工具。使用调试器?这是一个完全虚假的答案:传递
NUL
字符的地址(正如示例代码所做的)是完全有效的。那么什么会导致strcmp出错呢?
./symtab_parse test_file