2013-01-01から1年間の記事一覧

リンカによるシンボル解決(4)文字列リテラル

文字列リテラルのシンボル解決について見ていきます。 1 #include <stdio.h> 2 3 const char *dummy_string; 4 const char *string; 5 6 int main() 7 { 8 dummy_string = "123456"; 9 string = "ABCDEF"; 10 11 printf("string = %p\n", string); 12 13 return 0; 14</stdio.h>…

リンカによるシンボル解決(3)ファイル内関数のCALL

今回は、関数の呼び出し部分の実行コードについて、リンク前とリンク後で比較してみます。 d: e8 f3 ff ff ff call 5 80483c1: e8 f3 ff ff ff call 80483b9 ありゃ、該当のコード「e8 f3 ff ff ff」には、まったく変化なしですね。局所変数の場合、オブジェ…

リンカによるシンボル解決(2)ファイル内変数のシンボル解決(後編)

変数の論理アドレスが実行コード中に埋め込まれる場所は、以下の.rel.text(再配置テーブル)で管理されます。 Relocation section '.rel.text' at offset 0x410 contains 2 entries: Offset Info Type Sym.Value Sym. Name 00000005 00000401 R_386_32 0000…

リンカによるシンボル解決(1)ファイル内変数のシンボル解決(前編)

以下は、あるオブジェクトファイルの機械語コードのダンプです。 $ gcc -c sample.c -Wall $ objdump -d sample.o -M intel (略) 00000000 <main>: 0: 55 push ebp 1: 89 e5 mov ebp,esp 3: 8b 15 04 00 00 00 mov edx,DWORD PTR ds:0x4 9: a1 08 00 00 00 mov e</main>…

自己参照構造体のエイリアス定義

自己参照構造体のエイリアスを定義するとき、構造体のタグ名とエイリアスを重複させないように、エイリアスの先頭に「_」(アンダースコア)をつけたものをタグ名とする定義を見かけますが・・・ /* ×悪い例 */ typedef struct _NODE{ int node_id; struct _…

ulimit(1)

システムリソースの上限を設定する。すべての情報を表示する。 $ ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 7826 max locked memo…

【ELF形式】.dynstr セクション

前回見たように、.dynstrセクションは、.dynsymセクションヘッダのsh_nameが参照する文字列(シンボル名)を格納しています。 # # .dynstr セクションヘッダ # $ od -x -A x -j0x123c -N0x28 sample 00123c 0056 0000 0003 0000 0002 0000 820c 0804 00124c …

【ELF形式】.dynsym セクション

セクションヘッダおよびセクションの内容をダンプしてみます。 # # .dynsym # # セクションヘッダ $ od -x -A x -j0x1214 -N0x28 sample 001214 004e 0000 000b 0000 0002 0000 81cc 0804 001224 01cc 0000 0040 0000 0006 0000 0001 0000 001234 0004 0000 …

【ELF形式】.gnu.hash セクション

セクションヘッダの内容をダンプしてみます。 # # .gnu.hash # # セクションヘッダ $ od -x -A x -j0x11ec -N0x28 sample 0011ec 0044 0000 fff6 6fff 0002 0000 81ac 0804 0011fc 01ac 0000 0020 0000 0005 0000 0000 0000 00120c 0004 0000 0004 0000 0012…

【ELF形式】.note.gnu.build-id セクション

「.note.*」セクションは、「注釈セクション」というものらしいです。「ORACLE Documentation リンカーとライブラリ 第7章オブジェクトファイル 注釈セクション」 http://docs.oracle.com/cd/E19620-01/805-5821/6j5ga47bq/index.html#chapter6-18048オブジ…

【ELF形式】.note.ABI-tagセクション

徹夜でやってて、たまに寝落ちが入ってきたので、そろそろ投げやりモードですが(笑)セクションヘッダのダンプ。 $ od -x -A x -w16 -j0x119c -N0x28 sample 00119c 0023 0000 0007 0000 0002 0000 8168 0804 0011ac 0168 0000 0020 0000 0000 0000 0000 00…

【ELF形式】ELFヘッダ(1)

ELF形式について、徹底的に調べ尽くしてみます。ELFヘッダの構造体の定義は、「/usr/include/elf.h」に、データ型の定義は「/usr/include/stdint.h」でそれぞれ定義されています。 /* /usr/include/elf.h */ 26 /* Standard ELF types. */ 27 28 #include <stdint.h> 2</stdint.h>…

【ELF形式】.interpセクション

前回は、.shstrtabセクションからセクション名を抽出し、セクションヘッダ一覧に代入しました。 オフセット 内容 サイズ 管理セクション名 0x0000114c セクションヘッダ0 28h(40d)バイト "\0" 0x00001174 セクションヘッダ1 28h(40d)バイト ".interp" 0x0000…

【ELF形式】セクションヘッダとセクションの関係

今回、セクションヘッダが30個あるという情報を、ELF形式ファイルの先頭から48(0x30)バイト目の位置にある2バイトの情報(e_shnum)から取得しましたが、これはつまり、セクション実体が30個あるということでもあります。セクションヘッダとは、それに対応…

【ELF形式】ELFヘッダ(2)

今回は、以下のソースコードをコンパイルして、そのバイナリを解析します。 /* sample.c */ 1 #include <stdio.h> 2 3 int main(void) 4 { 5 return 0; 6 } まずコンパイル。 $ gcc sample.c -o sample -Wallodコマンドで、実行ファイルの先頭にあるELFヘッダ(52バイ</stdio.h>…

関数の動的書き換え(1)

関数の内容を動的に書き換えることをやってみます。 サンプルソースは、「リンカ・ローダ実践開発テクニック」(p139)より。 /* overwrite.c */ 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 5 int value; 6 char buffer[100]; 7 8 void func1() { value += 1; }</stdlib.h></string.h></stdio.h>…

関数の動的書き換え(2)

前回は、関数の動的書き換えを行うプログラムを実行したところ、書き込み禁止領域に対して書き込もうとするため保護違反が発生し、プログラムはSIG_SEGVで終了しました。そこで、func1()が.textセクションではなく、.dataセクションに配置されるように、リン…

おすすめ本

・『C言語ポインタ完全制覇 (標準プログラマーズライブラリ)』(前橋 和弥/技術評論社)「ポインタでつまづく」ほどの初心者段階は卒業しており、ポインタ配列、配列へのポインタ、多次元配列は「C言語ユーザー」として一応使えてはいるが、この記述がコン…

-128〜127、0〜255のビットの動き

char、unsigned charの表現可能な数値の範囲は、 -128 0 127 255 CHAR +++++++++++------------- UCHAR -------------+++++++++++++charの0〜127がunsigned charの0〜127とビット列を共有しているのは当然ですが、 charの-128〜-1は、unsigned charの128〜25…

【配列とポインタ】第9回 配列とは概念である

前回までで、メモリ上のデータの参照/代入に必要な情報は、「位置」「長さ」「解釈の仕方」だ、と書きましたが、逆に言うと、その3つさえ分かれば、何でもできてしまいます。それがC言語の恐ろしいところですが…以下は、アドレス0x804A024に位置する1バイト…

【配列とポインタ】第8回 そもそも変数とは何か?(2)

今回は、変数の残りのキモである「データの長さ」「データを正しく解釈する方法」についてです。データの長さ前回は、メモリ上の特定領域にアクセスするための「位置情報」(アドレス)について書きました。この位置情報を使って、特定領域にアクセスすると…

【配列とポインタ】第7回 そもそも変数とは何か?(1)

今まで、さんざんポインタと配列をいじり倒しながら試行錯誤してきましたが、そろそろ「そもそも変数とは何か?」という本質論について考える時が来たようです。プログラミングの入門書によくある説明で、変数とは「番号のついた箱」と言われます。データ格…

【配列とポインタ】第6回 char **argvを実装してみる(2)

前回の擬似argv実装を、いい感じにリライトしてみた(つもり)です。 マジックナンバーがかっこ悪いですが、動的配列の機能はC99からなので使用禁止。使用する変数は、以下の通り。 変数 役割 char string 文字列の実体を格納する領域 char *arg_plist[] 各…

【配列とポインタ】第5回 char **argvを実装してみる(1)

main()の引数である、「char **argv」の擬似変数「char **argv2」を実装してみます。 引数文字列の実体をスタックの連続領域に作成し、 各文字列の位置情報を管理するポインタ配列を作成し、 ポインタ配列の位置情報をargv2に格納する という流れでやってい…

【配列とポインタ】第4回 式の展開規則(配列・ポインタ編)

式の展開規則実際のコーディングでは、扱う配列はたかだか二次元配列までがほとんどなので、一次元・二次元配列の展開手順は反復練習で身体で覚えてしまって、それ以上の多次元配列になれば、以下の展開規則を再帰的に当てはめて展開していけばいいかと思い…

【配列とポインタ】第3回 間接演算子は関数である

今まで見てきたように、間接演算子*の作用は、以下のようにまとめられると思います。char型配列の配列arrが以下のようにあるとき、 +------+------+------+------+------+ arr | arr0 | arr1 | arr2 | … | arrN | +------+------+------+------+------+式中…

【配列とポインタ】第2回 配列へのポインタ

式中において、ポインタに間接演算子*をつけると、参照先の値に展開される…というのは当たり前ですが、int型変数へのポインタに*をつけると、int型の値に展開される。 char型変数へのポインタに*をつけると、char型の値に展開される。 ポインタ型変数へのポ…

【配列とポインタ】第1回 配列

C言語中級者にとっての鬼門と言っても過言ではない、配列とポインタ絡みのところが、いつまで立ってもモヤモヤして気持ち悪い!ので、何回かに分けて、基礎からまとめてみたいと思います。宣言と初期化char型配列の宣言時の初期化子には、以下例のように文字…

sizeof演算子

以下について、sizeofでサイズを調べてみます。 文字リテラル 空文字 文字列リテラル char型配列 int型配列 int型二次元配列 int型二次元配列の最上位次元の先頭要素の間接参照 int型二次元配列の間接参照 char型配列の集合を管理するポインタ配列 char型配…

constの修飾対象

間接演算子*と、constが混在した場合の変数宣言について、まとめてみました。 # syntax constの修飾対象 1 const chat *p ポインタの参照先オブジェクト 2 char * const p ポインタ変数そのもの 3 const char * const p 1かつ2 ちなみに、以下のような記述も…