FromNandの日記

自分的備忘録

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

【x86アセンブラ】PUSH・POPの動作を少し細かく見てみる

今回考えるのは、PUSH・POPにおいてESPの変化と値を取り出すタイミングがどの順番で行われているかということだ。 実験に使用するコードはこれ。 .code32 .globl push_test, pop_test .text push_test: subl $4, %esp ## here! movl $0x12345678, (%esp) ## …

【x86アセンブラ】レジスタの内容を表示するプログラムを考えてみる

低レイヤの作業をしているとこういった関数が欲しくなる時があるので実装してみた。 まず、これがC言語側から呼び出す際に必要とする構造体と使用する関数のプロトタイプ宣言。 // search_regs.h #ifndef _SEARCH_REGS_H #define _SEARCH_REGS_H typedef str…

【x86アセンブラ】PUSHAL・POPALについて調べてみた【順番・レジスタの種類など】

この記事は32bitレジスタを対象に考えておりますのでご了承ください。 参考 : PUSHAD - Push All General-Purpose Registers x86には一括してレジスタを操作する命令PUSHAL・POPALがあるらしい。 それぞれが行う命令を分解して考えると、こうだ。 PUSHAL (PU…

【C言語マクロ】どのファイルの何行目から呼ばれているかを調べる方法

なんだか今は規格で廃止されているかもしれないけど、どのファイルのどの行から呼ばれたかを調べてくれるマクロが紹介されている。コンパイラが色々情報を補って実現されているものらしい。すごい。参考 : Finding out where a function was called from - E…

多次元配列の各点におけるアドレスを表示する

おそらく理解はできているのだが、実際に表示させてみる。 #include<stdio.h> int main(void){ int i; char array[10][10][10][10]; // arrayは「int(*)[10][10][10]」、&arrayは「int(*)[10][10][10][10]」、&array[0]はarrayと同様「int(*)[10][10][10]」を指してい</stdio.h>…

【Eli Bendersky】アセンブラレベルの面白い記事リンク

EliさんのサイトはArchives - Eli Bendersky's website。 32bitコンピュータで64bit命令をどのように実行しているか? 64-bit types and arithmetic on 32-bit CPUs - Eli Bendersky's website x86におけるスタックについて Where the top of the stack is o…

【C言語・アセンブリ】多次元配列のアクセスをアセンブラで見てみる

次のプログラムをアセンブルするといい。配列の各次元の要素数を変えてみると、プログラムが興味深く変化する。 #include<stdio.h> int main(void){ int i = 1, j = 2, k = 3; char a[10], b[10][10], c[10][10][10]; a[i] = 0xff; b[i][j] = 0xff; c[i][j][k] = 0xff</stdio.h>…

多すぎるmakefileを分割する方法

まずディレクトリdirのなかにディレクトリdir1とdir2が格納されていたとする。・dirの中にはmakefileしかない。・dir1にはsrc1,makefileが含まれている。・dir2にはsrc2,makefileが含まれている。 この時、いちいちmakefileの中でほかのディレクトリのファイ…

【Linux】パイプ機能とリダイレクトの優先順位について

linuxにはパイプというものがあり、例えば // prog1.c #include<stdio.h> int main(void){ printf("hello world!\n"); return 0; } // prog2.c #include<stdio.h> int main(void){ char c; while( (c = getchar() ) != EOF){ printf("%c", c); } return 0; } これをそれぞれコ</stdio.h></stdio.h>…

【C言語】C言語におけるキャストの働きについて調べてみた

キャストについてよくわかっていなかったので調べた。 僕がよくわかっていなかったのは、次の3点である。 ・「符号あり・符号なしの間におけるキャスト」 ・「サイズの異なるキャスト」 ・「キャストによってどんな機械語が生成されるのか」 また、ここで対…

【アセンブラ】GASにおけるljmpとljmplの違いについて

gasって意外にネット上に情報がないので、ここに忘れないうちに示しておく。 ljmp - オペランドのアドレスから続く4byteをeipにいれ、5-6byteをcsにいれる farjmp: #void farjmp(int eip, int cs) ljmp *4(%esp) ret ljmpl - オペランドは二つあり、一つ目を…

【アセンブラ】GASでのマクロ関数の書き方

基本的にはつぎのように書けばいいらしい。 .macro <マクロの名前> <可変の名前> ~処理~ call \<可変の名前> //\<可変の名前>で参照することができる。あとcall以外もOK ~処理~ .endm 実際の例で確認しておきたい。 .globl asm_inthandler21, asm_inthandler…

【C言語】仮引数と実引数の違い

仮引数は引数を受け取る側の関数の引数のことで、実引数は関数を呼び出す側で実際に渡す引数のこと。 int main(void){ func(1, 2); // 実引数1, 2 return 0; } void func(int a, int b){ // 仮引数a, b // 処理 } ちょいちょい出てくるけど忘れやすいので...

【C言語】浮動小数点数の内部表現について

floatは符号部1bit,指数部8bit,仮数部23bit doubleは上記の順番に1bit, 11bit, 52bit また、指数部にはバイアスがかかっておりfloatは-127、doubleは-1023 仮数部はアドレスが高位なほうから0.5, 0.25, 0.125....と2のマイナスの乗数で表される IEEEという団…

【C言語】ヘッダファイルの書き方

【1】すべてのヘッダファイルにはインクルードガードをつけるべき。 // これを書くことで重複インクルードがなくなる #ifndef _HEADER_H #define _HEADER_H // 処理を書いていく #endif 【2】あるヘッダファイルAが常にあるヘッダファイルBに依存するとき、…

x86アセンブラのPUSH・POPについての疑問を実験してみた!

まずひとつ目は「espをpushするときにespはpushする前に値が変更されるのか、それともpushした後に変更されるのか」という疑問です。答えを言ってしまうとespがpushされた後に値は変更されます。当然ですけど。つまり、espの値を表示する関数などを作りたい…

関数のポインタを返す関数へのポインタを返す関数を作ってみた

コードはこれ #include<stdio.h> void a(void){ printf("a\n");} void b(void){ printf("b\n");} void c(void){ printf("c\n");} void d(void){ printf("d\n");} void (*func(int num))(){ switch(num){ case 'a': return a; case 'b': return b; case 'c': return c;</stdio.h>…

リンカスクリプトで変数を定義し、それをCファイルで参照する方法

リンカスクリプトで変数を宣言するには ・.(ロケーションカウンダ)をインクリメントする方法 ・BYTE()、SHORT()、LONG()などのビルトイン関数を使う方法 の主に二つが存在する。 前者は初期値を設定しなくてよい場合に手頃だが、初期値も欲しい場合は後者を…

リンカスクリプトにおけるMEMORYコマンドの使い方

具体的に言うと「MEMORYコマンド」を使うらしい。 MEMORYコマンドとはこんなやつ MEMORY{ PHDR (r) : ORIGIN = 0x8048000, LENGTH = _elf_header_size TEXT (rx) : ORIGIN = ORIGIN(PHDR) + LENGTH(PHDR), LENGTH = 0x2000 - _elf_header_size RODATA (r) : …

リンカスクリプトのシンボル機能を使って各セクションのアドレスを表示してみる

リンカスクリプトにはいろいろな面白い機能がある。 今回はシンボルをリンカスクリプトで定義して、それをC言語側の関数から表示してみたい。 まず、リンカスクリプトはこれ。 SECTIONS{ . = 0x8048000 + SIZEOF_HEADERS; .text : { stext = .; *(.text) ete…

【GASアセンブラ】わかりにくい文法や豆知識を自分なりにまとめておく

・バイナリに特定のデータを詰め込む .skip n(, fill) .space n(, fill) ・文字列をバイナリに埋め込む .ascii "abc" (nullターミネートなし) .asciz "abc" (nullターミネートあり) .string "abc" (nullターミネートあり) https://stackoverflow.com/questio…

再配置可能コード(リロケータブルコード)と位置独立コード(PIC)の違いと解説

【解説】 そもそも、なんでこれらが必要になったのか? それは、昔はMMU(動的アドレス変換)などがなかったので、絶対アドレスを指定してしまうと、本当にそのアドレスでしか実行できなかった。 これは、アドレスが重複する2つのプログラムが同時に実行できな…

【ELF解析】ELF形式のバイナリを解析する際の手順について

ELF形式の解析を行う際の手順をまとめておきます。 まず、main関数で解析対象のバイナリをfopenします。 そしてfstatやmmapを利用してベタバイナリをメモリに確保したあと、ようやく解析が始まります。 int fd; struct stat sb; char *head; // 対象のELF形…

交換法則・結合法則・分配法則の定義について

交換法則 3 + 7 = 7 + 3 といったように、順番を交換できるという法則。 結合法則 (2 * 3) * 5 = 2 * (3 * 5) といったように、カッコをどこにつけても同じだという法則。 分配法則 3 * (5 + 2) = 3 * 5 + 3 * 2 といったように、カッコを外せるという法則。…

【C言語】構造体名は構造体への先頭アドレスを表すか?

構造体の文法について理解が及ばないところがあったので。 時に、下のプログラムは文法上の誤りを含んでいる。 #include<stdio.h> struct STR { int a, b, c; }; int main(void){ struct STR str; printf("str = %p, &str = %p, &str.a = %p\n", str, &str, &str.a); </stdio.h>…

バイナリ解析系コマンド(objdump readelf)などをまとめてみた

objdump 「-d」でテキスト領域だと思われるセクションのみをディスアセンブルする。 「-S」で可能であればソースコードとディスアセンブリしたものを表示する。このオプションでは暗黙に「-d」が指定される。 「-h」ではセクションの情報のみを表示する。 「…

Linuxにおけるアプリケーションの開始から終了まで

「Hello World」の本に書いてあったことを自分向けにまとめただけ。 簡単にするためにあえて省いたものやただ単に僕が間違えている可能性もあるのでご参考程度に^^ 【execve】 プログラムの実行はスタートアップ関数から行われると思われがちだが、実際には…

動的リンクと共有ライブラリ(GOT・PLT)について

プログラミングをやっているとしばしば出てくるこれらの単語... あまり意味が理解できていなかったのでまとめておきます。 また、次のサイトは非常にわかりやすく解説されている。 位置独立形式(PIC・PIE)の意味もちょっと分かったような気がする。 https://…

GCCのオプションについておさらいしておく

gccはコンパイルドライバと呼ばれ、プリプロセス・コンパイル・アセンブル・リンクといった作業を一挙に引き受けている。 実際には内部で適切なプログラムを呼び出しており、コンパイラはcc1、アセンブラはas、リンカはcollect2などが使用されているらしい。…

【objdump】フラットなバイナリファイルをディスアセンブルする方法

これまでPEやELFといったファイルは解析してきたが、それらの形式に沿っていないファイルを解析したことは少なかったのでまとめておく。 ちなみに環境はx64を前提とする。 https://stackoverflow.com/questions/1737095/how-do-i-disassemble-raw-16-bit-x86…