思いついたのでやりました
環境
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みたいなのが入ってたし)
先人たちってすげー