繁体   English   中英

尝试遍历共享库的符号表时的C指针分段原因

[英]C pointer segmentation cause when tries to walk symbol table of shared library

我想知道是否有人能想到一个原因,当指针为:1.非NULL指针时,如何从指针读取会导致分段。

我想做的事情是遍历共享库并访问其符号表。 当我尝试访问ELF哈希表以获取符号表中的符号数量时,就会发生分段。

在x86平台上没有注意到这一点。 仅在MIPS64平台上执行时才会发生。

该代码基于以下链接: 如何在ELF可执行文件中解释动态符号表?

static void
btrace_dl_symtab_walk(struct dl_phdr_info *info,
                  btrace_dl_lib_t *ctx) {
ElfW(Dyn*) dyn;
ElfW(Sym*) sym = NULL;
ElfW(Word*) hash;

ElfW(Word) sym_cnt = 0;
char* strtab = NULL;
char* sym_name = NULL;
unsigned int i;  
int j;

/*
 * Make indicator to show all of them acomplished before going forward
 */

for (j = 0; j < info->dlpi_phnum; j++) {
    if (info->dlpi_phdr[j].p_type == PT_DYNAMIC) {
        dyn = (ElfW(Dyn)*)(info->dlpi_addr +  info->dlpi_phdr[j].p_vaddr);
        while(dyn->d_tag != DT_NULL) {
            if (dyn->d_tag == DT_HASH) {
                hash = (ElfW(Word*))dyn->d_un.d_ptr;
                if (!hash) {
                    return;
                }

                /*
                 * SEGFAULT happens here
                 */
                printf("Before Seg Fault\n");
                sym_cnt = *(hash + 1);      //<=============== This line causes seg fault
                printf("Never reached here\n");
            } else if(dyn->d_tag == DT_GNU_HASH) { 
                /*
                 * Since there is no simply way to find entry count
                 * in GNU hash table, we have no choice but to
                 * count by hand
                 */
                uint32_t *buckets;
                uint32_t *hashval;
                hash = (ElfW(Word*))dyn->d_un.d_ptr;
                buckets = hash + 4 + (hash[2]*sizeof(size_t)/4);
                for (i = sym_cnt = 0; i < hash[0]; i++) {
                    if (buckets[i] > sym_cnt) {
                        sym_cnt = buckets[i];
                    }
                }
                if (sym_cnt) {
                    sym_cnt -= hash[1];
                    hashval = buckets + hash[0] + sym_cnt;
                    do {
                        sym_cnt++;
                    } while (!(*hashval++ & 1));
                }
                sym_cnt += hash[1];
            }else if (dyn->d_tag == DT_STRTAB) {
                strtab = (char*)dyn->d_un.d_ptr;
            } else if (dyn->d_tag == DT_SYMTAB) {
                sym = (ElfW(Sym*))dyn->d_un.d_ptr;
                break;
            }
            dyn++;
        }
        break;
    }
}

// Other acitivities
}

欢迎任何指导。 谢谢

我想知道是否有人能想到一个原因,当指针为:1.非NULL指针时,如何从指针读取会导致分段。

指针不是NULL事实并不意味着您可以从中读取。 由于多种原因,它可能是无效的,例如

char *p = mmap(...);
munmap(p, ...);

char c = p[0];  // p points into unmapped memory, SIGSEGV likely.

在x86平台上没有注意到这一点。 仅在MIPS64平台上执行时才会发生。

您是否在两个平台上使用相同版本的GLIBC?

如果我没记错的话,旧版本的GLIBC不会重定位DT_HASH ,但是新版本会重定位。 这也可能是特定于体系结构的。

您将需要打印hash的值,并将其与dyn的值进行比较。 如果hash很小,则需要通过info->dlpi_addr对其进行重定位。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM