2016-09-07 11 views
2

在进行函数调用时,我正在丢失(全局)变量的地址(在共享对象中定义)。为了证明它,我有意将变量num_accounts的值设置为55,当函数get_num_accounts()开始执行时,指向此变量的指针被错误地接收。我的证据是这个GDB会话:在函数调用期间获取变量的地址不正确

accounts_init() at accounts.c:31 
31  err_code=read_accounts(); 
(gdb) print num_accounts 
$1 = 0 
(gdb) print &num_accounts 
$2 = (account_idx_t *) 0x7ffff767c640 <num_accounts> 
(gdb) set var num_accounts=55 
(gdb) print num_accounts 
$3 = 55 
(gdb) s 
read_accounts() at accounts.c:66 
66  err_code=get_num_accounts(&num_accounts); 
(gdb) s 
get_num_accounts (num_accounts_ptr=0x604780 <num_accounts>) at accounts.c:119 
119  *num_accounts_ptr=0; 
(gdb) print num_accounts 
$4 = 55 
(gdb) print *num_accounts_ptr 
$5 = 0 
(gdb) 
(gdb) print num_accounts_ptr 
$6 = (account_idx_t *) 0x604780 <num_accounts> 
(gdb) 

变量NUM_ACCOUNTS的地址是0x7ffff767c640,但我得到0x604780执行该功能时,为什么这样一个奇怪的事情发生?

功能get_num_accounts()是本的源代码:

err_code_t get_num_accounts(account_idx_t *num_accounts_ptr) { 
    err_code_t err_code; 
    uint32_t file_size; 
    div_t div_result; 
    unsigned short number; 

    *num_accounts_ptr=0; 
    err_code=get_dir(); 
    if (err_code!=ERR_NO_ERROR) return err_code; 
    err_code=get_file(ACCOUNTS_FILENAME,sizeof(ACCOUNTS_FILENAME),&file_size); 
    if (err_code!=ERR_NO_ERROR) return err_code; 

    div_result=div(file_size,sizeof(tbl_account_t)); 
    if (div_result.rem!=0) { 
     return ERR_BAD_CONFIG_FILE_FORMAT; 
    } 
    number=div_result.quot; 
    *num_accounts_ptr=number; 
    return ERR_NO_ERROR; 
} 

类型account_idx_t定义为:

typedef   unsigned short   account_idx_t; 

全局变量NUM_ACCOUNTS在accounts.c文件在限定的开始:

account_idx_t  num_accounts=0; 

Bas理论上,函数做的是在读取文件之前获取文件的大小并计算文件包含的记录数。 (它的数据库)

这是调用代码,这卡列斯get_num_accounts()函数:

err_code_t accounts_init(void) { 
    err_code_t err_code; 

    err_code=read_accounts(); 
    if (err_code!=ERR_NO_ERROR) return err_code; 

    return ERR_NO_ERROR; 
} 
err_code_t read_accounts(void) { 
    err_code_t err_code; 
    int ret; 

    err_code=get_num_accounts(&num_accounts); 
    if (err_code!=ERR_NO_ERROR) return err_code; 
    if (num_accounts==0) return ERR_NO_ERROR; 

    int fd=open(filename_buf,O_RDONLY); // filename_buf is global, it holds filename from previous call 
    if (fd==-1) { 
     return ERR_SYS_ERROR; 
    } 
    ret=read(fd,accounts,sizeof(tbl_account_t)*num_accounts); 
    if (ret==-1) { 
     return ERR_SYS_ERROR; 
    } 
    ret=close(fd); // TO_DO: validate return value of close(fd) 
    if (ret==-1) { 
     return ERR_SYS_ERROR; 
    } 
    return ERR_NO_ERROR; 
} 

我编译具有-fPIC标志库:

[[email protected] src]$ make accounts.o 
gcc -g -ffunction-sections -fdata-sections -Wall -Wextra -Wunreachable-code -Wmissing-prototypes -Wmissing-declarations -Wunused -Winline -Wstrict-prototypes -Wimplicit-function-declaration -Wformat -D_GNU_SOURCE -fshort-enums -fPIC -c accounts.c 

没有另一个'num_accounts'符号在源代码中的任何地方,我再次检查:

[[email protected] src]$ nm *o|grep num_accounts 
0000000000000000 T get_num_accounts 
0000000000000000 B num_accounts 
[[email protected] src]$ 

任何有关进一步调试步骤的建议?

+0

我不擅长GDB。所以可能是一个愚蠢的问题。你正在进入'get_num_accounts'或者正在跨越。如果您在阅读'* num_accounts_ptr'时正在逐步完成,则超出范围。 – MotKohn

+0

@MotKohn用's'命令进入它,以便跨过它是命令'n' – Nulik

+0

对不起再次提问,但0x7ffff767c640对我来说看起来不是一个有效的地址。有点太高了,不是吗? – MotKohn

回答

1

在gdb正在查看的可执行映像中,有两个不同的符号,名为num_accounts。 gdb直接告诉你,只要你告诉它打印一些具有指针类型值的东西,gdb就会在可执行文件的符号表中对该地址进行反向查找,如果发现某些东西,它会打印出名称在<>中的符号。所以,当你做的gdb命令:

(gdb) print &num_accounts 
$2 = (account_idx_t *) 0x7ffff767c640 <num_accounts> 

GDB是告诉你,0x7ffff767c640点在符号称为num_accounts。同样,

(gdb) print num_accounts_ptr 
$6 = (account_idx_t *) 0x604780 <num_accounts> 

告诉你一个符号,它也被称为num_accounts0x604780点。

现在的问题是如何得到两个具有相同名称的符号。大地址0x7ffff767c640将在一个共享库中,因为共享库加载在这样的地址上。小地址0x604780位于基本可执行文件中。

+0

我认为在输出“(num_accounts_ptr = 0x604780 )”中所说的是num_accounts_ptr指向的是“num_accounts”,它是一个全局变量。实际上,我将全局变量本身作为参数传递。我不需要这样做,因为变量是全局变量,我可以在任何地方访问它,但将它传递给参数也是有效的。我没有重复的符号,否则我将无法链接 – Nulik

+0

共享库和可执行文件之间的重复符号不会阻止链接,除非您使用适当的链接标志专门请求它。尝试在可执行文件和共享库上运行nm并查看每个中定义的符号。 –