Today アクセスカウンター Yesterday アクセスカウンター

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書く事で広告が消せます。

gasでcrtを書く

前回のコードをgas(GNU assembler)で書き直した。また、以下の点が異なる。

- gasはmasmのような高級な構文(invokeや.ifなど)を持っていないので、全てより低水準な表現で書き直されている。

ループなどをアセンブラで書くのは面倒だったので、Cで書ける部分はCで書いた。(crt.c)

- 関数の戻り値をチェックしている。
- main()に渡されるargvの型を、wchar_t *argv[]ではなく、より標準的なchar *argv[]にした。

CommandLineToArgvW()で確保された、ワイド文字列の領域を、WideCharToMultiByte()でマルチバイト文字列に変換した後のargvで破壊的に更新することが合法なのかどうかは謎なのだが、呼び出し側の責任でLocalFree()することが義務付けられているようなので、問題無いと思う。

- MinGWのgcc 3.4.5では、main()のプロローグ部分で_allocaの呼び出しが要求されるので、適当に実装。

test.c
extern void *stdout;
#define EOF (-1)

int main(int argc, char *argv[])
{
    int i;

    for (i = 0; i < argc; i++) {
        if (fputs(argv[i], stdout) == EOF) return 1;
        if (fputs("\n", stdout) == EOF) return 1;
    }
    return 0;
}

コンパイルは以下のように行う。
$ gcc -fno-builtin -c test.c
$ gcc -fno-builtin -c crt.c
$ as crt.s -o crt1.o
$ ld crt.o crt1.o test.o -lkernel32 -lshell32 --entry=mainCRTStartup
crt.c
typedef unsigned short wchar_t;

char *strcpy(char *s1, char *s2)
{
    char *p;

    p = s1;
    while (*s1++ = *s2++);
    return p;
}

int ArgvWtoArgvA(int argc, wchar_t *argvW[])
{
    int i;
    char buf[1024];

    for (i = 0; i < argc; i++) {
        if (wcstombs(buf, argvW[i], 1024) == -1) return 1;
        strcpy((char *)argvW[i], buf);
    }
    return 0;
}

crt.s
.intel_syntax noprefix

.equ STD_INPUT_HANDLE,  (-10)
.equ STD_OUTPUT_HANDLE, (-11)
.equ STD_ERROR_HANDLE,  (-12)
.equ EOF, (-1)
.equ NULL, 0
.equ CP_OEMCP, (932)

.data
.global _stdin
_stdin:  .long 0
.global _stdout
_stdout: .long 0
.global _stderr
_stderr: .long 0

.text
.global _fputs
_fputs:
        push    ebp
        mov     ebp,    esp
        sub     esp,    8
        push    [ebp+8]
        call    _lstrlenA@4
        mov     [ebp-4],eax
        push    NULL
        lea     eax,    [ebp-8]
        push    eax
        push    [ebp-4]
        push    [ebp+8]
        push    [ebp+12]
        call    _WriteFile@20
        cmp     eax,    0
        jne     1f
        mov     eax,    EOF
1:      mov     esp,    ebp
        pop     ebp
        ret

.global _wcstombs
_wcstombs:
        push    ebp
        mov     ebp,    esp
        push    0
        push    0
        push    [ebp+16]
        push    [ebp+8]
        push    -1                       # null terminated
        push    [ebp+12]
        push    0
        push    CP_OEMCP
        call    _WideCharToMultiByte@32
        cmp     eax,    0
        jne     1f
        mov     eax,    -1        
1:      mov     esp,    ebp
        pop     ebp
        ret

.global mainCRTStartup
mainCRTStartup:
        push    ebp
        mov     ebp,        esp
        sub     esp,        16
        call    _GetCommandLineW@0
        cmp     eax,        NULL
        jne     1f
        jmp     fatal_error
1:      mov     [ebp-4],    eax
        lea     eax,        [ebp-8]
        push    eax
        push    [ebp-4]
        call    _CommandLineToArgvW@8
        cmp     eax,        NULL
        jne     2f
        jmp     fatal_error
2:      mov     [ebp-12],   eax
        push    eax
        push    [ebp-8]
        call    _ArgvWtoArgvA
        add     esp,        8
        cmp     eax,        0
        je      3f
        jmp     fatal_error
3:      push    [ebp-12]
        push    [ebp-8]
        call    _main
        add     esp,        8
        mov     [ebp-16],   eax
        push    [ebp-12]
        call    _LocalFree@4
        cmp     eax,        0
        je      4f
        jmp     fatal_error
4:      mov     eax,        [ebp-16]
        jmp     5f
fatal_error:  
        mov     eax,        2
5:      push    eax
        call    _ExitProcess@4
        mov     esp,        ebp
        pop     ebp
        ret

.global ___main
___main:
        push    STD_INPUT_HANDLE
        call    _GetStdHandle@4
        mov     _stdin, eax
        push    STD_OUTPUT_HANDLE
        call    _GetStdHandle@4
        mov     _stdout, eax
        push    STD_ERROR_HANDLE
        call    _GetStdHandle@4
        mov     _stderr, eax
        ret

# for gcc 3.4.5
.global __alloca
__alloca:                          # void *_alloca(size_t size)
        pop     ecx                #     [esp]    : return address
        mov     eax,    [esp]      #     [esp+4]  : size
        add     eax,    3          # 4 byte alignment
        and     eax,    0xfffffffc #     (size + 3) & 0xfffffffc
        sub     esp,    eax        # allocate
        lea     eax,    [esp+4]    # return value
        jmp     ecx                # ret

コメント

Secret

プロフィール
  • Author:あろは (alohakun)
  • 京都のデバッガベンダーに勤めるアラサー会社員。

    本ブログの内容は、あくまでも個人的な感想や意見であり、会社の意見を代表するものでは一切ありません。

    最近は会社の方のブログをメインに更新しています。

    KMC Staff Blog

    連絡先 : alohakun ___at___ gmail.com
    mixi : http://mixi.jp/show_friend.pl?id=182927
    twitter : http://twitter.com/alohakun













    あわせて読みたい


    この日記のはてなブックマーク数


    スカウター : ホワット・ア・ワンダフル・ワールド


    Map
FC2カウンター
ブロとも申請フォーム

この人とブロともになる

最近のコメント
リンク
最近のトラックバック
人生の残り日数
日本人男性の平均寿命は 28700日.
RSSフィード
カテゴリー
  1. RSSリーダー