LoginSignup
0
0

More than 1 year has passed since last update.

fprintf関数とかを使わずに文字列を書き込んでいきたい

Posted at

思いついたのでやりました

環境

Ubuntu20.04

NASM version 2.14.02

方法

アセンブラを書き
Systemcallを呼んで
標準出力やファイルに書き込みます

フォーマットを文字列にするのはめんどくs…難しいのでvsprintfを使います
(Systemcall使わないし、いいよね)

ソースコード

printk.h
#include <stdio.h>
#include <stdarg.h>
/**
 * 
 * ファイル構造体とvsprintfを使うためにstdioとstdargを使う
 */

int fprintk(FILE* fp, const char* format, ...);
writek.h
int Writek(int fd, void* ptr, long size);
printk.h
#include "printk.h"
#include "Writek.h"

/**
 * vsprintf用のバッファ
 */
char s[1024];

/**
 * 自作fprintf関数本体
 * vsprintfでフォーマットと可変長配列を文字列にし
 * Writek関数でファイルや標準出力などに書き込んでいく
 */
int fprintk(FILE* fp, const char* format, ...){
    int result;
    va_list va;
    int size;

    va_start(va, format);
    size = vsprintf(s, format, va);
    va_end(va);
    if(size < 0){
        result = size;
    }else{
        result = Writek(fp->_fileno, s, size);
    }
    return result;
}
Writek.asm
bits 64

section .text

global Writek

;Writek関数本体
;mov rax,1でWriteのシステムコールをしていして
;SystemCallで実行
;C言語ってこういうところ便利で、レジスタはABIが勝手に必要なところに割り振ってくれる

Writek:
    mov rax, 1
    syscall
    ret

実行してみる

Hello.c
#include "printk.h"

int main(int argc, char const *argv[])
{
    fprintk(stdout, "Hello World My System\n");
    for(int i = 0; i < 10; i++){
        fprintk(stdout,"%d\n",i);
    }
    return 0; 
}

とりあえず適当なファイルを書いて

コンパイル

$gcc -c printk.c
$nasm -f elf64 Writek.asm
$gcc -c Hello.c
$gcc -o Hello Hello.o printk.o Writek.o

(自分の環境だとelf64で実行できたけど 環境次第では別のを指定しなきゃいけないかも)

そして実行

$./Hello

実行結果


$./Hello
Hello World My System
0
1
2
3
4
5
6
7
8
9

まとめ

とりあえず作ってみて、アセンブラとC言語ってうまく出来てるんだなって思った(もっとアセンブラ書くことを覚悟してた)
あとはFILE構造体からファイルを指定するint値を取得するためにFILE構造体の中身を見てみたけど
Javaとかみたいにクラスがないからかすっごく複雑と実感した
(LinkedListみたいなのが入ってたし)
先人たちってすげー

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0