GAS(GNU Assembler)で構造体にアクセスする

環境はWindows7(32bit)&cygwingcc/gas(x86)で試した。

".struct"で構造体を定義し、その後サイズ(item_length)を算出する。

そして".bss"セクションに構造体名(item)でitem_length分メモリーを確保(".space")する。

後は、レジスタにitemのアドレスを代入し、間接アドレッシングでメンバーにアクセスする(この例ではitem.item2に0x05を代入している)。

.struct 0
item_start:
item1:
        .struct item1 + 12
item2:
        .struct item2 + 2
item3:
        .struct item3 + 8
item_end:
item_length = item_end - item_start

.bss
item:
        .space item_length

.text
        movl    item,%eax
        movw    $0x05,item2(%eax)

コンパイルし逆アセンブラをしてみると確かにitem2の位置(12→0xc)分を考慮したコードが生成されていた。

$ objdump.exe -d st.o
セクション .text の逆アセンブル:

00000000 <.text>:
   0:   a1 00 00 00 00          mov    0x0,%eax
   5:   66 c7 40 0c 05 00       movw   $0x5,0xc(%eax)
   b:   90                      nop

次のステップとして、アセンブラからC言語の構造体(ヘッダに定義)にアクセスしたいのだけど、やり方がよくわからない。インラインアセンブラを使えばこんな苦労しないのだけど...。

参照:
Ian Lance Taylor - Re: structures in assembly code
Using as: Struct

xv6をWindows環境(cygwin環境)で手軽にビルドする

cygwingcc(binutil)だと出力可能なバイナリーフォーマットが原因で、自作OSのビルドが出来ないケースが多々ある。

そこで、cygwinportsを利用しgccを導入することでこの問題を解決する。

ついでに今回はxv6をビルドしてみた。

cygwin & apt-cyg の導入までは色々解説があるので適当にお願いします。

クロス開発環境を導入する。

$ apt-cyg update -m ftp://ftp.cygwinports.org/pub/cygwinports
$ apt-cyg install linux-i686-gcc-core
(省略)
$ i686-pc-linux-gnu-gcc -v
組み込み spec を使用しています。
COLLECT_GCC=i686-pc-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-pc-linux-gnu/4.8.2/lto-wrapper.exe
ターゲット: i686-pc-linux-gnu
configure 設定: /usr/src/ports/linux-i686-gcc/linux-i686-gcc-4.8.2-1/src/gcc-4.8.2/configure --srcdir=/usr/src/ports/linux-i686-gcc/linux-i686-gcc-4.8.2-1/src/gcc-4.8.2 --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdir=/usr/libexec --datadir=/usr/share --localstatedir=/var --sysconfdir=/etc --libdir=/usr/lib --datarootdir=/usr/share --docdir=/usr/share/doc/linux-i686-gcc --htmldir=/usr/share/doc/linux-i686-gcc/html -C --build=i686-pc-cygwin --host=i686-pc-cygwin --target=i686-pc-linux-gnu --without-libiconv-prefix --without-libintl-prefix --with-sysroot=/usr/i686-pc-linux-gnu/sys-root --with-build-sysroot=/usr/i686-pc-linux-gnu/sys-root --libexecdir=/usr/lib --enable-shared --enable-shared-libgcc --enable-static --enable-languages=c,c++,fortran,ada,java,go,lto,objc,obj-c++ --enable-version-specific-runtime-libs --disable-alsa --enable-libada --enable-libgomp --enable-libitm --enable-libjava --enable-libquadmath --enable-libquadmath-support --enable-libssp --enable-default-preferences-peer=file --disable-java-awt --disable-jni --with-arch=i686 --with-tune=generic --with-dwarf2 --with-ecj-jar=/usr/share/java/ecj.jar --with-gnu-as --with-gnu-ld --with-cloog-include=/usr/include/cloog-isl --with-system-zlib
スレッドモデル: posix
gcc バージョン 4.8.2 (GCC)

導入成功!

xv6のMakefileを書き換えビルドする。

xv6のソースを展開し、Makefileの"TOOLPREFIX"を"TOOLPREFIX = i686-pc-linux-gnu-"と設定。

後はmakeするだけで完成する

$ make
i686-pc-linux-gnu-gcc -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pic -O -nostdinc -I. -c bootmain.c
i686-pc-linux-gnu-gcc -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pic -nostdinc -I. -c bootasm.S
i686-pc-linux-gnu-ld -m    elf_i386 -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o
i686-pc-linux-gnu-objdump -S bootblock.o > bootblock.asm
i686-pc-linux-gnu-objcopy -S -O binary -j .text bootblock.o bootblock
./sign.pl bootblock
boot block is 447 bytes (max 510)
i686-pc-linux-gnu-gcc -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer -fno-stack-protector   -c -o bio.o bio.c
(省略)
i686-pc-linux-gnu-gcc -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer -fno-stack-protector   -c -o wc.o wc.c
i686-pc-linux-gnu-ld -m    elf_i386 -N -e main -Ttext 0 -o _wc wc.o ulib.o usys.o printf.o umalloc.o
i686-pc-linux-gnu-objdump -S _wc > wc.asm
i686-pc-linux-gnu-objdump -t _wc | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$/d' > wc.sym
i686-pc-linux-gnu-gcc -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer -fno-stack-protector   -c -o zombie.o zombie.c
i686-pc-linux-gnu-ld -m    elf_i386 -N -e main -Ttext 0 -o _zombie zombie.o ulib.o usys.o printf.o umalloc.o
i686-pc-linux-gnu-objdump -S _zombie > zombie.asm
i686-pc-linux-gnu-objdump -t _zombie | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$/d' > zombie.sym
./mkfs fs.img README _cat _echo _forktest _grep _init _kill _ln _ls _mkdir _rm _sh _stressfs _usertests _wc _zombie
used 29 (bit 1 ninode 26) free 29 log 10 total 1024
balloc: first 394 blocks have been allocated
balloc: write bitmap block at sector 28
dd if=/dev/zero of=xv6.img count=10000
10000+0 レコード入力
10000+0 レコード出力
5120000 バイト (5.1 MB) コピーされました、 0.271833 秒、 18.8 MB/秒
dd if=bootblock of=xv6.img conv=notrunc
1+0 レコード入力
1+0 レコード出力
512 バイト (512 B) コピーされました、 0.0163324 秒、 31.3 kB/秒
dd if=kernel of=xv6.img seek=1 conv=notrunc
248+1 レコード入力
248+1 レコード出力
126980 バイト (127 kB) コピーされました、 0.0212534 秒、 6.0 MB/秒

xv6.imgが無事に完成!ちゃんと起動する!

参考にできる64bit自作OSの例

ソースコードが公開されていると、わからないことを確認できるので助かる。
Programming a 64-bit Operating System
→64bit OSの作成方法を説明している。アセンブラはNASMを使っている模様。
https://github.com/neri/op05
→国産64bit OSとして初期のころ有名だったOrangePekoのfork
GitHub - swetland/xv6: 64bit port of xv6
→有名なXV6の64bit移植版

64bit OS(x64 Kernel)の自作のために(1)

前から気になっていたところ、以下Blogで実際に動くコード(x86->x64)が公開されていたので、BlogとOSDEVの記事を参考にしながら動かしてみた。

ビルド環境はWindows7 with Cygwin(x86_64-pc-linux-gnu-gcc ver 4.8.2)

このとき、はまったのがx64でのGDT(Global Descriptor Table)の設定。
IDT(Interrupt descriptor table)と同じくbaseのアドレス設定値が64bitアドレスに拡張されているという別の記事を信じてしまったところ、うまくいかず四苦八苦。真相はx64でGDTのbase/limitは拡張されていないが正しい。

以下、処理の流れ。

  1. GRUB2で32bit Kernel(multiboot形式)をロードする。(以下32bitコード)
  2. 32bit/64bit用のGDTを作成する。
  3. 32bit用のGDTを読みこむ & セグメントを設定する。
  4. Pagingの有効化()
  5. PAEの有効化(CR4を設定する)
  6. Long Mode(64bitコードに移行 このとき64bitのセグメントを読み込ませる)のコードにJMPする。
  7. C言語のKernelを呼び出す。

参照:
Linuxをはじめよう!:1から創る自作OS x86_64 01h
Creating a 64-bit kernel - OSDev Wiki

「USB-Blasterもどき」をPIC/AVRライターが無い環境から作成する。

ここしばらく色々ありすぎて、バタバタしていたがやっと落ち着いてきたので、久々に更新することにした。

なんとなくFPGA/CPLDに興味を持ったが入門キットでも結構な値段がする。

安いキット(キットで約1,600円)はあるが書き込むための機材(USB-Blaster)が別途必要であり、結局良い値段になってしまう。

<MAX2 CPLDボードの特徴>
570ロジックエレメント(LE)、76I/OのEPM570T100C5Nを搭載
...(省略)

MAX2 CPLD

調べるとこの互換機を作っている方の記事を見つけたが、当方の環境にはこの作成に必要なPIC18F14k50にファームウェアを書き込めるライターが無い…。

・概要
AlteraのUSB接続JTAGインターフェース、「USB-Blaster」を安価なPICマイコンエミュレートします。
Alteraの純正ツールでCPLDFPGAの書き込み、デバッグがUSB一本でできます。

USB-Blasterもどきの製作 - sa89a.net

そこで色々と検討した結果、以下順序でPICライターが作れるハズと、勉強がてら試してみることにした。

  • hidspx内蔵のEGGライタ機能でHIDaspxを作成する(AVRライターを作成する)

→「http://www-ice.yamagata-cit.ac.jp/ken/senshu/sitedev/index.php?AVR%2FHIDaspx#content_1_15」を参考にした。

この方法を採用したのは、USBシリアル変換(秋月電子製)が利用できる点である。

  • HIDaspx(AVRライター)でAVRにHIDaspxに書き込む。

→「http://www-ice.yamagata-cit.ac.jp/ken/senshu/sitedev/index.php?AVR%2FHIDaspx#content_1_6」を参考にした。

この作業が必要なのは、EGGライタ機能で書き込んだ場合、書き込み後のベリファイができないためである。

  • HIDaspxでPIC(PIC18F14k50)に「USB-Blasterもどき」のファームウェアを書き込む(AVRライターでPICに書き込む)

→「PICspx - AVR etc」を参考にした。

これでPIC(PIC18F14k50)に「USB-Blasterもどき」のファームが書き込めた。