2016-09-07 16 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()このあるのソースコード:

typedef   unsigned short   account_idx_t; 

グローバル変数NUM_ACCOUNTS個がでaccounts.cファイルで定義されている:

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は以下のように定義されます初め:

account_idx_t  num_accounts=0; 

Bas関数が何をしているのかは、ファイルのサイズを取得し、ファイルを読む前にそのファイルに含まれるレコードの数を計算することです。 (そのデータベース)

そして、これはget_num_accounts()関数をcalles、呼び出し元のコード、次のとおりです。私は-fPICフラグとライブラリをコンパイルしています

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; 
} 

[[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という2つの異なるシンボルがあります。 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_accountsと呼ばれているシンボルであなたに0x604780ポイントを伝えます。

ここで問題は、同じ名前の2つのシンボルがどのように得られたかです。大きなアドレス0x7ffff767c640は、共有ライブラリがそのようなアドレスにロードされるため、共有ライブラリに格納されます。小さなアドレス0x604780はベースの実行可能ファイルにあります。

+0

GDBが言っているように、 "num_accounts_ptr = 0x604780 "の出力では、num_accounts_ptrがグローバル変数である "num_accounts" 。実際、グローバル変数自体のパラメータとして渡しています。変数はグローバルでどこでもアクセスできますが、パラメータに渡すことも有効なので、これを行う必要はありません。私は重複したシンボルを持っていません。それ以外の場合はリンクできません。 – Nulik

+0

共有ライブラリと実行ファイルの間に重複するシンボルがあっても、実行可能ファイルと共有ライブラリの両方でnmを実行し、それぞれに定義されているシンボルを確認してください。 –

関連する問題