機械語初心者がアセンブラを作ってみる

機械語初心者がアセンブラを作ってみるだけのブログです。ひつまぶしひつまぶし

第15回 da,exe Ver.0.0.236.0

f:id:kmynews:20130601210918p:plain

 

女に約束をすっぽかされた記念(´・ω・`)

 

いやほんとは

ニモニックですとかレジスタですとか

そういう識別ができる関数作ってきたんですけど

上の画面ではまだ使ってないので

実質第14回と同じという。

 

あっファイル名とEOFが分かるようになりましたよー^^

 

コードジェネレートをどのタイミングでやろうか悩んでるなう

第14回 da.exe Ver.0.0.191.0

f:id:kmynews:20130601155655p:plain

 

 

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回 誰得

 誰得だと突っ込まれそうですが

f:id:kmynews:20130521230201p:plain

ビルドするたびにバージョン番号を自動で足していくツールを作ってみました。

 

‥‥‥‥

 

いや、あの、debug$Sに大きな数字を書きたくなったので。

というか5万とか大きな数字に憧れたので。

雰囲気です、雰囲気(汗

 

間違ったプログラムでも正常にビルドされたらビルド番号が増えます。

今日は40回くらいビルドし直しましたが、

なかなか思ったとおりの動作になりません。

 

オペランドレジスタだけを指定した時はうまくいくんですが

即値を指定したらなぜかエラーが出ます(´・ω・`)

 

どうせコンパイラの踏み台にするので

踏み台に必要な必要最低限の機能だけを実装するつもりなので

仮にこのまま飽きずに作って完成したとしても

アセンブラとしては実用的にはならないと思います。

 

それはそうと、

アセンブラ(da.exe)の名前、

「三日坊主」ではセンスが無いので

どうせ途中で飽きる」に変えました。

 

(もし飽きなければ)

リンカ→「どうせもう飽きる」(dl.exe)

コンパイラ→「どうせすぐ飽きる」(dc.exe)

っていう名前つけたいと思います。

どうせ飽きるシリーズでDA Projectです。

無論「どうせすぐ飽きる」が、そのままプログラミング言語の名前になります♪

 

アセンブラのda.exeについてるaは、アセンブラのaなので 

第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 固定?

 

また、オブジェクトファイル名とアセンブラ名の間にもこんなコードがあったんですが

 

f:id:kmynews:20130519140557p:plain

 

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)

アセンブラの概形もできたので

アセンブラ開発と機械語解析を並行して行いまーす。

 

f:id:kmynews:20130519112450p:plain

 

こちらの解析を行いましたー。

えーと、こちらには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で指定するのか‥‥めんどい

けど機械語には区切りっていうものがないから、こういう長さのデータも書かなきゃいけないという。

 

ところで

 

ところで

 

ところで

 

f:id:kmynews:20130519113626p:plain

 

わ・か・ら・ん☆

 

これ、ネットで調べたら

なーんか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 → 知らんがな