第15回 da,exe Ver.0.0.236.0
女に約束をすっぽかされた記念(´・ω・`)
いやほんとは
ニモニックですとかレジスタですとか
そういう識別ができる関数作ってきたんですけど
上の画面ではまだ使ってないので
実質第14回と同じという。
あっファイル名とEOFが分かるようになりましたよー^^
コードジェネレートをどのタイミングでやろうか悩んでるなう
第14回 da.exe Ver.0.0.191.0
Visual Studio 2012に移行してみた。
これまではコンパイルもコマンドライン作業だったので
方向キーでコマンドを選ぶの大変だったんですけど
VSのおかけで
F5でコンパイルと実行が同時に出来るようになって‥‥ううっ
VS移行のためだけにビルド番号30ほど消費したっていうのは内緒
とりあえず
トークン分析のあたりをいじってました。
基礎的なところはあらかた終わったので
あとはこれに肉付けするだけ(`・ω・´)
アセンブリの機械語出力処理を書くまで秒読み。(汗
それはそうと
C言語のdumpbinは怖くてとてもできない的なことを言った気がするんですが
cl.exeで生成したオブジェクトファイルは
textセクションがほんとに必要最低限で
余計なコードもなかったので
cl.exeでも.objならdumpbin余裕じゃん
って話になったんだ。
わざわざml64.exeで書かなくても
Cコンパイラちゃんが作ったコードをdumpbinすれば余裕じゃん
って話になったんだ。
なんで
C言語で
適当にコードを書いて
test64.objをdumpbinしたらあら不思議
main:
0000000000000000: 48 83 EC 28 sub rsp,28h
0000000000000004: 48 8D 0D 00 00 00 lea rcx,[$SG2871]
00
000000000000000B: E8 00 00 00 00 call printf
0000000000000010: 33 C0 xor eax,eax
0000000000000012: 48 83 C4 28 add rsp,28h
0000000000000016: C3 ret
( ゚д゚)
忘れてたああああああああああああああああああああああああああああ
(※この前載せたアセンブリにはスタックを元に戻す add はありませんでした)
死んでお詫びするしか
第13回 da.exe Ver.0.0.117.0
いえ、
実は
アセンブラ作り以外にも
やることがありまして
思った以上に進まないorz
いっそのこと
これを卒業研究にして
開発時間稼ぎたいとも思ったんだけど
卒業研究は就職したい企業の業務内容に合わせたほうがいいって
友達に言われたので‥‥。
一応(これでも)PCソフト制作希望なんだけど、
COFFの知識なんてまず必要なさそうな分野だからなぁ(´・ω・`)
そろそろ飽きるかも。
プログラムの大半を書き直して
いずれコンパイラを作る時にコードの一部を移植することを見越して
行解析法を単純にニモニック名とオペランドに分ける手法から
トークン分割に変えてみたり。
あと、ファイル単位で行なうアセンブリ読み込み処理を
再帰化を見越した設計にしてみたり。
いろいろいじってた。
トークン分割処理はまだ書いてる途中だから
要するにアセンブルできなくなった(キリッ
拙いコードだけど
何かに使えそうな関数晒しとく。
戻り値が辞書順じゃないので場合によっては修正の必要あるかもしれない。
僕の場合はただ一致してるかしてないかだけで十分なので。
トークン分割の時に使ったので。
なんか一行コメントをあらわすセミコロンに
全角文字も使えるようにしようとして大変なことになったので。
というかこのへんに1時間もかけた。死にたい。
すでに標準ライブラリに入ってるよねさすがに‥‥
//
// 文字列の後方一致を判定
//
int strbcmp (char *text, char *key)
{
int i, n, len;
// 文字列長を取得
len = strlen (key);
n = strlen (text);
// 文字列長が条件に合っているか
if (n < len) return 1;
// 実際に調べる
for (i=0; i<len; i++)
if (text[n-i-1] != key[len-i-1])
return -1;
// 合格
return 0;
}
第12回 誰得
誰得だと突っ込まれそうですが
ビルドするたびにバージョン番号を自動で足していくツールを作ってみました。
‥‥‥‥
いや、あの、debug$Sに大きな数字を書きたくなったので。
というか5万とか大きな数字に憧れたので。
雰囲気です、雰囲気(汗
間違ったプログラムでも正常にビルドされたらビルド番号が増えます。
今日は40回くらいビルドし直しましたが、
なかなか思ったとおりの動作になりません。
即値を指定したらなぜかエラーが出ます(´・ω・`)
どうせコンパイラの踏み台にするので
踏み台に必要な必要最低限の機能だけを実装するつもりなので
仮にこのまま飽きずに作って完成したとしても
アセンブラとしては実用的にはならないと思います。
それはそうと、
アセンブラ(da.exe)の名前、
「三日坊主」ではセンスが無いので
「どうせ途中で飽きる」に変えました。
(もし飽きなければ)
リンカ→「どうせもう飽きる」(dl.exe)
コンパイラ→「どうせすぐ飽きる」(dc.exe)
っていう名前つけたいと思います。
どうせ飽きるシリーズでDA Projectです。
無論「どうせすぐ飽きる」が、そのままプログラミング言語の名前になります♪
第11回 COFFEEオブジェクトファイルの解析(5)
今日はもう時間がないので
手短に概要だけ。
結論から言うと
@comp.id=コンパイラの固有ID?
@feat.00=知らんがな
ということでおしまいになりました。
バージョン4のMASMで作ったオブジェクトファイルには
@feat.00はなかったし
同じコンパイラで作ったオブジェクトファイル間では
この2つは同じになるし
もろもろ考えてこんな結果になりました。
@comp.idはなんとなく分かったので
これから作るアセンブラでもこっそり適当な数字を
入れようかなと思ってるんですが
@feat.00についてはどういう意味があるのかついに分からなかったので
もう、これから作るアセンブラでは
@comp.idだけでいいんじゃないかと
いうことになりました。
ちなみにボーランド C Compilerで作ったオブジェクトファイルには
両方とも入っていなかったので
これら2つはマイクロソフトの作ったソフトが使っているのかなと思います。
せっかくなので
これから作るアセンブラの方でも
後から作る自作のリンカに渡すデータとかもろもろを定義する
独自のセクションを作ろうかなと思ってます。
それについてはリンカを作るところまでやる気が継続してから考えるとして。
とりあえずそろそろアセンブラ作りに打ち込みます。
第10回 COFFオブジェクトファイルの解析(4)
dumpbinですら解析されないdebug$sセクション。
アセンブルのデータが入ってるという線でいってみました。
ml64.exeでアセンブルしたオブジェクトファイルを解析してて
まったく何もわからないわけなんですが
cl.exe(Cコンパイラ)でコンパイルしたアセンブラっぽいやつのオブジェクトファイルまで引っ張りだして比べた結果、次の可能性が分かりました。
04 00 00 00 固定?
F1 00 00 00 固定?
6E 00 00 00 セクション終端までの相対アドレス
33 00 オブジェクトファイル名終端のNULL文字までの相対アドレス
01 11 00 00 00 00 固定?
また、オブジェクトファイル名とアセンブラ名の間にもこんなコードがあったんですが
MASM Ver.11:
37 00 3C 11 03 02 00 00 D0 00 00 00 00 00 00 00 00 00 0B 00 00 00 27 C6 01 00
Cコンパイラ Ver.17:
3A 00 3C 11 00 62 00 00 D0 00 11 00 00 00 27 C6 01 00 11 00 00 00 27 C6 01 00
Cコンパイラ Ver.16:
3A 00 3C 11 00 22 00 00 07 00 10 00 00 00 6F 76 01 00 10 00 00 00 6F 76 01 00
コンパイラの違いじゃなかったらすまん(´・ω・`)
でも、Cコンパイラは同じ情報を2回繰り返してるんだなーと思った。何の意味があるか分からない。
けど
右から8番目と16番目にコンパイラのバージョンが入ってるっていうのは分かった。
0B 00 00 00 27 C6 01 00←27 C6 01 00は固定かなと思ってたらそうでもなかった
というか10進数に直したら全部コンパイラのビルド情報だったわこれ
MASMのバージョンが 11.00.50727.1だったので
0B 00 11
00 00 00
27 C6 50727
01 00 1
ということになっただ
つまりコンパイラのビルドバージョンを書いてるわけかここ。
Cコンパイラが2回繰り返してる理由は分からんけど。
残った
37 00 3C 11 03 02 00 00 D0 00
について
先頭の37 00は、そこからコンパイラ名の終端NULLまでの長さ
っていうのは分かったけどその後が続かない。
でも、とりあえずコンパイラ関連だろうということで
もう放棄することにした。
なんとかならないのかなぁここんとこ
シンボルテーブル最初の@comp.idと@feat.00についてもいろいろ調べてみたけど
結局分からずしまい。
IMAGE_SYMBOL構造体のValueメンバだけが違って後は同じ、っていうとこまで分かったので
あとはこのValueがどうやって決まるかを調べないと
ああめんどい(´・ω・`)
追記:@comp.idと@feat.00に対して、ここの値を直接書き換えてリンク&dumpbinするという強硬手段に出ることにした。実行はしないからなっ!今は試す時間がないのでまた後で
第9回 COFFオブジェクトファイルの解析(3)
アセンブラの概形もできたので
こちらの解析を行いましたー。
えーと、こちらには2つの構造体がありましてー
typedef struct _IMAGE_SYMBOL {
union {
BYTE ShortName[8];
struct {
DWORD Short; // if 0, use LongName
DWORD Long; // offset into string table
} Name;
DWORD LongName[2]; // PBYTE [2]
} N;
DWORD Value;
SHORT SectionNumber;
WORD Type;
BYTE StorageClass;
BYTE NumberOfAuxSymbols;
} IMAGE_SYMBOL;
typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF {
BYTE bAuxType; // IMAGE_AUX_SYMBOL_TYPE
BYTE bReserved; // Must be 0
DWORD SymbolTableIndex;
BYTE rgbReserved[12]; // Must be 0
} IMAGE_AUX_SYMBOL_TOKEN_DEF;
それっぽいのをwinnt.hから探すだけの簡単なお仕事です(泣)
ちなみにセクションでない場合はIMAGE_SYMBOL1つだけでいいみたい。
というかIMAGE_AUX_SYMBOL_TOKEN_DEF構造体は、IMAGE_SYMBOLのNumberOfAuxSymbolsで数を指定できるみたい。
なんとなくで分かってくれ(切実)
ち~~~ん(笑)
名前が8文字より長いシンボルは
シンボルテーブルの後ろに文字を書くスペースがあって
そこへのポインタを書くのかしら
っていう
あと、textセクション本体の最後に書いてあるシンボルテーブルっていうのは
リロケーション=再定義なんとか?で
この構造体を使ってるみたい。
typedef struct _IMAGE_RELOCATION {
union {
DWORD VirtualAddress;
DWORD RelocCount; // Set to the real count when IMAGE_SCN_LNK_NRELOC_OVFL is set
} DUMMYUNIONNAME;
DWORD SymbolTableIndex;
WORD Type;
} IMAGE_RELOCATION;
わかったよーなわかんないよーな(´・ω・`)
この構造体の数はセクションヘッダのnumber of relocationsで指定するのか‥‥めんどい
けど機械語には区切りっていうものがないから、こういう長さのデータも書かなきゃいけないという。
ところで
ところで
ところで
わ・か・ら・ん☆
これ、ネットで調べたら
なーんかCodeViewみたいなのを使ってるらしい。
なので
その線でいろいろ調べたけどわかんない(´・ω・`)
.debug$Sセクションであることは分かったけど
資料見ても項目はあったのに何も書いてないよヽ(`Д´#)ノ
textセクション本体の後にあるdataセクションで
文字列なんとかいろいろ定義した後に
debug$Sセクションがきてるわけなんですが
04 00 00 00 F1 00 00 00 6E 00 00 00 33 00 01 11 00 00 00 00
こちらーがー問題の機械語となってるわけですが
それっぽいのを見つけてきた(dbgHelp.h)
typedef struct _MODLOAD_DATA {
DWORD ssize; // size of this struct
DWORD ssig; // signature identifying the passed data
PVOID data; // pointer to passed data
DWORD size; // size of passed data
DWORD flags; // options
} MODLOAD_DATA, *PMODLOAD_DATA;
けど
これ、サイズ的には合ってるけど
なんか違和感がするんですーするんですー
そもそも構造体の名前からしてアレ。
困ったなぁー
とりあえず機械語を適当に分解すると
04 00 00 00
F1 00 00 00
6E 00 00 00
33 00 01 11
00 00 00 00
になるのかしら。
これ、test64.objの話ですが
いろいろあってたまたま「test64_2.obj」を作ったら
その中にはこう書かれてました。
04 00 00 00
F1 00 00 00
70 00 00 00
35 00 01 11
00 00 00 00
となっておりますが
もしも先ほどの構造体でおkだとしたら
この構造体の直後にオブジェクト名の絶対パス名が書いてあったので
test64.objとtest64_2.objとじゃサイズが2つ変わっちゃうわけですよ。
なのでdataとsizeメンバの説明ができ‥‥るかなぁ。
気になるのが
35 00 01 11のあたりかなぁ。
上位(なのか?リトルエンディアンでこう呼んでいいのか?)の01 11
これが何を意味するのか
これを読んだあなた、どうか真相を暴いて下さい。
それだけが私の望みry
実はここ、dumpbinでも解析されないorz
どうすりゃいいってんだよこれ(´・ω・`)
もう1つ気になるのがですね
このdebug$Sセクションの終端が
6E 00 00 00の次のアドレスに6Eを足したものと一致するんですね。
構造体の終端でも先頭でもなく、6E 00 00 00という一変数の終端のアドレスが
基準になっているって
なんかおかしくありません?
そもそもこれは構造体ではないとか
2つの構造体で成っているとか
考えられるわけですが
もう1つ過程を。
33 00 01 11はDWORDではなく
33 00のWORD?かな?という。
少なくとも33 00っていうのは
この後にあるobjファイル名の文字列の長さを表していると思うんですが
その後の01 11から計算を始めると
アドレスを33進めたらオブジェクトファイル名終端のNULL文字と一致するんです。
01 11を入れずにその後の37 00を含むべきかも難しいところですし
オブジェクトファイル名の前の01 11 00 00 00 00が
何を表すかも不明ですし。
全然わかんないですし(´・ω・`)
誰か‥‥誰か資料を僕にくれるんだ‥‥!
※つ・い・き☆
04 00 00 00 → 4バイト後の6E 00 00 00、間接的に次のセクションの先端を指している?
F1 00 00 00 → 終端のアドレス+F1が、シンボルテーブルにおける.dataセクションのアドレスと一致
01 11 00 00 00 00 → 知らんがな