ページへ戻る

− Links

 印刷 

hideyosi​/osalink1でお勉強 :: OSASK計画

osaskwiki:hideyosi/osalink1でお勉強

ページ内コンテンツ
  • なんすかこれ?
  • sjisconv.exe
  • cc1.exe
  • gas2nask.exe
  • nask.exe(本名 nasuka )
    • エラーの解析と対処
  • ld.exe
    • なんなの?それは???
    • さて! いざ、リンク!
  • やべ・・・いろいろゴチャゴチャになってきたぞw
    • tolower関数
    • fscanf関数
  • 最後! 例のバッファ!
  • 誰かCに詳しい人検証してくれww

なんすかこれ? anchor.png[1]

hideyosiのお勉強のページ♪

GOとかtolsetとかの中にosalink1.exeっつーのがある。これは予測だけど、ポツンと.cファイルがあるだけってことから、たぶんGOとか(Kタンの自前開発環境)が出来る前に作られたものだと思う。

(そうなると、MinGWだとか、別のきれいに整った開発環境で作られてるはず。そういう完成した環境ではみーんな付いてるので、.cをひとつ作ればツルっとexeが作れちゃうと。その証拠にMinGWだとペロっとコンパイルできて動いちゃうw)

・・・こいつが、28GOでコンパイルできない・・・

なんかムカつく!

っつーわけで、よい教材になるかなと思って28GOでコンパイルできるように弄っていこうかと。こういうわけ!

ちなみに、ここからダウンロードできるぞよ?

http://sourceforge.jp/projects/osask/downloads/45468/osalink1_src_1.0.tar.gz/[2]

Page Top

sjisconv.exe anchor.png[3]

こいつはなにをやっているのか。たしか、ソースコード内にShift-jisの文字が入っているとうまくないってんでそれをお掃除してくれるor変換してくれるツールだったはず。まずはコイツで・・・

..\z_tools\sjisconv.exe -s osalink1.c osalink1.ca

osalink1.caの中身を見てみると日本語部分がぜーんぶ「\203」とかそういうのになってる。変換されたわけですなw(なんだべこれ? rawとかそういうのになるのかな??)

Page Top

cc1.exe anchor.png[4]

CのソースなんだからCでコンパイルすると。(あったりまえだぁw)

osalink1のソース内に、ctype.hが宣言されてる。これちょっと迷ったんだけど、MinGWではここ削除してもそのままコンパイルできちゃうので神頼み的にこれで進めちゃいます・・・

ここで復習。Cコンパイラはなにをしてるのか。総合環境だと忘れがちなんだけど、Cコンパイラは実行ファイルなんかつくってくれない

あくまでも、Cソースを元にアセンブラコードを作ってくれるだけなのだ。

こんなことしてアセンブラコードであるosalink1.gasを作ると・・・

..\z_tools\cc1.exe -I../z_tools/win32/ -Os -Wall -quiet -o osalink1.gas osalink1.ca
Page Top

gas2nask.exe anchor.png[5]

cc1で出来上がったosalink1.gas。これは先に述べたように、単なるアセンブラコードに過ぎない。その証拠に、エディタで開けたりするw

さて。28GO(GO 0023)のCコンパイラは元々gccだった。そのため、このコンパイラが吐き出すアセンブラコードはgccとペアで使うことが想定されている GAS(The GNU Assembler)用のものなのだ。

つまり、このosalink1.gasをGASでコンパイル(アセンブル)すれば実行ファイルが出来上がると。未確認ですサーセン

・・・しかし! 我らが28GO(笑)にはGASよりカッチョイイnasuka(NASK)があるのだ!

・・・そんなわけで。GAS用のアセンブラコードをnasuka用に変換してやればいいわけ。それがgas2naskの役目ね。

..\z_tools\gas2nask.exe -a osalink1.gas osalink1.nas

これで、nasukaでアセンブルできるコード、osalink1.nasが出来上がったと。

Page Top

nask.exe(本名 nasuka ) anchor.png[6]

アセンブラのnask.exeでアセンブルすると、これで初めてバイナリコードが生成されるわけ。

..\z_tools\nask.exe osalink1.nas osalink1.o
NASK : TMPBUF is not enough

・・・順調だったのに・・・orz・・・エラーで止まってしまった・・・

Page Top

エラーの解析と対処 anchor.png[7]

このセクションは移動or削除ora大改編が予想されますのでその旨ご容赦w

「NASKのエラーなんて、ググってもなんもわかんないよおぉぉ(泣」

・・・って思ってたら、それはそれ。インターネットってスゲーよね? めっけた。

http://www.rapuos.net/scrsvr.html[8]

これによると、外部変数が多いとNASKがこのエラーを吐くらしいことがわかった。外部変数ってなに??? 調べてみると、グローバル変数のことをこう呼ぶことがあるらしい。

osalink1.cの内部をざーーっと眺めてみる。グローバル変数? ほとんど使ってないじゃん。容量が上がるほどの変数なんて・・・お???

これかなぁ。先頭で

#define	BUFSIZE		2 * 1024 * 1024

こんなことをやっている。これが大きすぎるってことなのかなぁ。試しに、この行を1024とか小さい値と置き換えて・・・

うはぁ!!! NASKのコンパイルが通ったぞ???

もちろん単にここを小さくするのは問題のはずだ。なぜこの値を指定していたのかは、ちゃんと意味があるんだからね。・・・でも、とにもかくにも、ここで宣言されているによってNASKの挙動が左右されるってことだけは確認できた。正式な対処はちょっと先送りで、進めまするw

Page Top

ld.exe anchor.png[9]

さていよいよldの登場ですw

Page Top

なんなの?それは??? anchor.png[10]

今、まだ積み残しの問題があるとしても、とにもかくにもnasuka(NASK)がアセンブル(コンパイル)を完了してosalink1.oを作ってくれました。これはもうバイナリです。(いままでと違ってエディタでは開けませんよw バイナリエディタでないと)

じゃあ、このバイナリは動かせるのでしょうか?

答えは No! です。

なぜかって? このosalink1.oにはプログラムが書かれていないからですw

たとえば。「xxxをディスクに書き込みする」という命令があるとします。仮に、その命令は、

51 01 89 C2 C1 FA 10 C1 F8 18 88 51 02 88 41 03 5D C3 55 89 E5 8B 55 08 5D 0F B6 02 0F B6 52 01

こんなんだとしますよね? (もちろん機械語ですよw) この命令をはじめから実行してゆくと、ディスクが動いて磁気ヘッドに電流を流し、書き込みを行うとします。

・・・しかし、この段階では、この命令はosalink1.o内には書かれていないのです。

同じように、他の命令も書かれていません。

  • 画面に一文字書き出せ
  • メモリをxxxバイト確保しろ
  • 書かれている文字を数値に変換して計算し、結果を再び文字に変換しろ
  • etc・・・・

osalink1.o内には様々な動作をする命令がちゃんと沢山書かれているのですが、上記のようなよく使われる大事な命令達は書かれていません。では、そういう命令はどうするのでしょう? これから自分で別に作るのでしょうか??

もちろんそれも可能です。しかし、こういうよく使われる・いろいろなプログラムから共通で統一的に使われる命令達はライブラリ(図書館?)と呼ばれる別のファイルに、あらかじめ書かれ、すでに用意されているのです。

ldは「リンカ」と呼ばれるプログラムで、こういったバラバラの部品として完成しているファイル(中間ファイル・オブジェクトファイルなどと呼ばれる)をお互いに合体させ、最後にキチンと本当に動くプログラムに組み立てるという働きをするのです。

Page Top

さて! いざ、リンク! anchor.png[11]

..\z_tools\ld.exe  --stack 0x2000000 -o osalink1.exe osalink1.o ..\z_tools\win32/libmingw.lib

・・・ダメだった・・・・orz・・・(やっぱみようみまねじゃアカンなw)

..\z_tools\ld.exe: warning: cannot find entry symbol _mainCRTStartup; defaulting to 00401000
osalink1.o(.text+0x85):osalink1.ca: undefined reference to `__main'
osalink1.o(.text+0xba):osalink1.ca: undefined reference to `fopen'
osalink1.o(.text+0xdf):osalink1.ca: undefined reference to `fscanf'
osalink1.o(.text+0xf4):osalink1.ca: undefined reference to `fopen'
osalink1.o(.text+0x11d):osalink1.ca: undefined reference to `fread'
osalink1.o(.text+0x125):osalink1.ca: undefined reference to `fclose'
osalink1.o(.text+0x164):osalink1.ca: undefined reference to `tolower'
osalink1.o(.text+0x262):osalink1.ca: undefined reference to `fclose'
osalink1.o(.text+0x270):osalink1.ca: undefined reference to `__stderr'
osalink1.o(.text+0x275):osalink1.ca: undefined reference to `fprintf'

さて。このエラーはなんだろうか?

上記の命令だと、osalink1.oとlibmingw.libを合体させてosalink1.exeを作り出せってしてるんだけど、ldはいざ合体させ始めると、

「おいおい! osalink1.o内で、fopenって命令を使ってるじゃないかよ! osalink1.o内にも、libmingw.lib内にも、その命令は書かれてないぞ? 命令が間違ってるんじゃね? もしくは、これらが書かれているライブラリを教えてよ!」

と、こういう答えを出して来たと。こういうわけ。

他のライブラリを指定してあげれば、それらから命令を拾ってきて合体させてくれる。これでOKだ!!!

..\z_tools\ld.exe -s -Bdynamic --stack 0x2000000  -o osalink1.exe osalink1.obj ..\z_tools\win32\w32clibc.lib ..\z_tools\win32 \golibc.lib ..\z_tools\win32\libmingw.lib
osalink1.obj(.text+0xda):osalink1.ca: undefined reference to `fscanf'
osalink1.obj(.text+0x15f):osalink1.ca: undefined reference to `tolower'
osalink1.obj(.text+0x41a):osalink1.ca: undefined reference to `tolower'
osalink1.obj(.text+0x45d):osalink1.ca: undefined reference to `tolower'

・・・ダメですた・・・orz・・・

あっれぇ?? 今、ざーっと調べてみたんだけど、そういえばz_tools\win32\stdio.h内にはfscanfって関数、ないような・・・

さらに発覚! tolower関数は、あの、ctype.hで定義されている命令なんだって!? ・・・うわぁ・・・まいったなぁ・・・

Page Top

やべ・・・いろいろゴチャゴチャになってきたぞw anchor.png[12]

Page Top

tolower関数 anchor.png[13]

逆に言えば!!

ctype.hをインクルードしてるけど、この関数さえあればいいわけでしょ?  自作 できんか? これ?

tolower関数は、文字が大文字なら小文字に変換。大文字以外なら、そのままの値を返すというものだよね?

A~Zってーのは、41h~5Ahまで。で、a~zまでは61h~7Ahまでだよね? おぉ!綺麗に20h差で揃ってるじゃんwww

char tolower_hide(char moto){
    if ( (moto > 0x41) && (moto < 0x5a ) ){
        return moto + 0x20;
    }
    else{
       return moto;
    }
}

・・・これじゃダメか???

ぶははは。なんかうまく行きそうな予感wwwww

Page Top

fscanf関数 anchor.png[14]

うーーーん・・・・・・・(汗

fscanfそのものはなんかけっこう複雑なもののように思う。・・・でもさぁ。なにも丸々搭載することはない・・・よね??

osalink1.c内ではfsnanfはこんな形で使われている。

	for (i = 0; fscanf(fp0, " %s", fname) == 1; i++) {
		fp1 = fopen(fname, "rb");
		if (fp1 == NULL) {

トーシローのオイラも目には、これはosalink.optを一行づつ読み込んで、その読み込んだ文字列と同じ名前のファイルのオープンを試みている・・・というゆうに読める。んん?? 一行???

・・・これ、fgets()じゃダメなの?(幸いstdio.hにはfgets関数がある)

なんでKタンはfgets()を使わずにfscanf()を使ったんだろう?なにか意味がきっとあるはず・・・

とにもかくにも!!!!!

こんなことしたら、コンパイルが通った。

	fp0 = fopen(optfile, "r");
	if (fp0 == NULL) {
		fprintf(stderr, "Can't open \"%s\".\n", optfile);
		return 1;
	}
	//	for (i = 0; fscanf(fp0, " %s", fname) == 1; i++) {
	for (i = 0; fgets(fname,32,fp0) != NULL; i++) {
		fp1 = fopen(fname, "rb");
		if (fp1 == NULL) {

さーて。乱暴者のオラはこれでOSASKをコンパイルしてみようwwww

ダメか・・・

どうも、fgetsだと改行コードが入り込むらしい。そんならってんで、こんな改行コード抜きを載せてみる。

	for (i = 0; fgets(fname,32,fp0) != NULL; i++) {

	  //改行コードの引っこ抜き
	  for ( i2 = 31; i2 != 0; i2--){
	    if ( fname[i2] == 0x0a ) fname[i2] = 0;
	    if ( fname[i2] == 0x0d ) fname[i2] = 0;
	  }

		fp1 = fopen(fname, "rb");
		if (fp1 == NULL) {
err1:
			fclose(fp0);

・・・やっぱだめだなぁ・・・orz

わからんなぁ・・・・・・。こうしてみると・・・

	strcpy (fname,"base.exe");                  osalink.optの一行目
	fp1 = fopen(fname,"rb");
	if (fp1 != NULL){
	  fprintf(stderr, "testOpenOK!\n", fname);        ちゃんとオープンが成功してくれる!
	  fprintf(stderr, "nagasa=%d\n", strlen(fname));     長さは8と表示される
	  fclose(fp1);
	}

	//	for (i = 0; fscanf(fp0, " %s", fname) == 1; i++) {
	for (i = 0; fgets(fname,32,fp0) != NULL; i++) {

	  //改行コードの引っこ抜き
	  for ( i2 = 31; i2 != 0; i2--){
	    if ( fname[i2] == 0x0a ) fname[i2] = 0x0;
	    if ( fname[i2] == 0x0d ) fname[i2] = 0x0;
	  }

		fp1 = fopen(fname, "rb");
		if (fp1 == NULL) {
err1:
			fclose(fp0);
			fprintf(stderr, "Can't openaaa \"%s\".\n", fname);          オープンに失敗する
			fprintf(stderr, "nagasa=%d\n", strlen(fname));              長さも同じ8。
			return 1;
		}

なぜ読み込んで改行抜きをしたfnameではエラーになるんだろう?????

こうやったらうまくいった!!! ・・・・でも納得できない・・・なんでだろう???

	  strcpy (fname2,fname);
		fp1 = fopen(fname2, "rb");
Page Top

最後! 例のバッファ! anchor.png[15]

このbuf0って、文字通り、対象ファイルを読み込んだものを格納するバッファだよね?? で!

static unsigned char buf0[BUFSIZE];

この命令で、2 × 1024 × 1024バイトの空文字が格納された文字変数を用意したわけだよね?(しかもグローバル変数)

・・・グローバル変数じゃないものにすればOK??

そんなわけで、こんなことしてみた。すると・・・・

const int main(int argc, char **argv)
{
	FILE *fp0, *fp1;
	int i, i2,j, k, size, totalsize = 0;
	unsigned char fname[32], name[8], c;
	unsigned char fname2[32];
	unsigned char bufX[2*1024*1024];

おぉ!bufXは使っていないんだけど、とにもかくにもこうやってグローバルではない変数しさえすれば、エラーを吐かないぞ? つまり、大きさが問題なんじゃなくて、でかいグローバル変数が問題ってことじゃないか!

なぜbuf0はわざわざグローバル変数になってるんだろ? それは、他の関数内でも使われてるからだよね?

const int script(char *opt, char *inp, char *out)
/* スクリプトが4KBを超えたら死にます */
{
	unsigned char *buf = buf0 + 4 * 1024, *scr0 = buf0, *scr1, *s, *s1;
	FILE *fp;
	int size, memofs, filofs;

・・・あれ? この、script関数内だけじゃないか!!!!

だったらさぁ。こうやって、script関数の引数に、buf0のアドレス(ポインタ)を渡してあげればそれでいいんじゃないの??

const int script(char *opt, char *inp, char *out, char *helmes_buf)
/* スクリプトが4KBを超えたら死にます */
{

	unsigned char *buf = helmes_buf + 4 * 1024, *scr0 = helmes_buf, *scr1, *s, *s1;
	FILE *fp;
	int size, memofs, filofs;

うぎゃあぁぁぁぁぁぁぁぁぁぁぁぁ!!!!! 動いた! OSASKがうごいたぞおぉぉぉぉ!!!!!

Page Top

誰かCに詳しい人検証してくれww anchor.png[16]


Last-modified: 2010-01-18 (月) 00:00:00 (JST) (103d) by lina