筆者は、こういうのをやろうと思った。
foo.c
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char **argv) {
if (argc < 2) {
static char msg[] = "Usage: $0 FILE\n";
write(2, msg, sizeof(msg)-1);
return 1;
}
int myfd = openat(AT_FDCWD, argv[1], O_RDONLY);
if (myfd < 0) {
static char msg[] = "Could not open\n";
write(2, msg, sizeof(msg)-1);
return 1;
}
char buf[4096];
ssize_t n = read(myfd, buf, sizeof(buf));
if (n<0) {
static char msg[] = "Read error\n";
write(2, msg, sizeof(msg)-1);
} else {
write(1, buf, n);
if (n > 0 && buf[n-1] != '\n') write(1, "\n", 1);
}
if (close(myfd) < 0) {
char msg[] = "Close error\n";
write(2, msg, sizeof(msg)-1);
}
}
なんでかって?暇だからである。
筆者は適当にいろいろと調べた。その結果、次に示すことが分かった。
- AArch64などLinuxカーネルにおいて新しく実装されたアーキテクチャのものは新しいシステムコールに統一されたこと
- openシステムコールはなくopenatを使うように求められてること
- read、openat、closeのシステムコール番号はそれぞれ63、56、57であること
書いた
foo.s
.data
.L.errorUsage.msg:.ascii "Usage: $0 FILE\n"
.L.errorUsage.msg.len = . - .L.errorUsage.msg
.L.errorOpenFile.msg: .ascii "Open error\n"
.L.errorOpenFile.msg.len = . - .L.errorOpenFile.msg
.L.warnReadError.msg: .ascii "Read error\n"
.L.warnReadError.msg.len = . - .L.warnReadError.msg
.L.warnWriteError.msg: .ascii "Write error\n"
.L.warnWriteError.msg.len = . - .L.warnWriteError.msg
.L.warnCloseError.msg: .ascii "Close error\n"
.L.warnCloseError.msg.len = . - .L.warnCloseError.msg
.L.buf: .ds.b 4096
.L.buf.len = . - .L.buf
.text
.globl _start
_start:
ldr x0,[sp]
cmp x0,2
b.lt .L.errorUsage
mov x0,-100
//
// argc: i32, argv: [*:0][*:0]const u8
ldr x1,[sp,16]
mov x2,xzr
//
// openat
mov x8,56
svc 0
tbnz w0,31,.L.errorOpenFile
mov x19,x0
// x19 = myfd
// x0 = myfd
ldr x1,=.L.buf
ldr x2,=.L.buf.len
mov x8,63
svc 0
mov x20,x0
// x20 = retval of read()
tbz w0,31,.L.myfdOk
bl .L.warnReadError
b .L.writeOk
.L.myfdOk:
mov x0,1
ldr x1,=.L.buf
mov x2,x20
mov x8,64
svc 0
tbz w0,31,.L.writeOk
bl .L.warnWriteError
.L.writeOk:
mov x0,x19
// close
mov x8,57
svc 0
tbz w0,31,.L.finally
bl .L.warnCloseError
.L.finally:
mov x0,0
.L.exit:
mov x8,93
svc 0
.L.errorUsage:
mov x0,2
ldr x1,=.L.errorUsage.msg
ldr x2,=.L.errorUsage.msg.len
.L.error:
mov x8,64
svc 0
mov x0,1
b .L.exit
.L.errorOpenFile:
mov x0,2
ldr x1,=.L.errorOpenFile.msg
ldr x2,=.L.errorOpenFile.msg.len
b .L.error
.L.warnReadError:
ldr x1,=.L.warnReadError.msg
ldr x2,=.L.warnReadError.msg.len
.L.warn:
mov x0,2
mov x8,64
svc 0
ret
.L.warnWriteError:
ldr x1,=.L.warnWriteError.msg
ldr x2,=.L.warnWriteError.msg.len
b .L.warn
.L.warnCloseError:
ldr x1,=.L.warnCloseError.msg
ldr x2,=.L.warnCloseError.msg.len
b .L.warn
書いた感想
デバッグは少し大変だった。
識別子の名付け方は便利になるようにした。
コードゴルフをやってるつもりはないが、次のコード
ldr x1,=.L.buf
するだけでなんかファイルサイズ増えたもんだと思った。何故ならtext領域に該当のアドレスを後置して埋め込むからだ。正直言って直接埋め込められるんだったら埋め込めることができたら良いのにとは思う。まあ無理ではないか。