150 lines
4.0 KiB
Plaintext
150 lines
4.0 KiB
Plaintext
#define SYS_WRITE $1
|
|
#define SYS_OPEN $2
|
|
#define SYS_CLOSE $3
|
|
#define SYS_FSTAT $5
|
|
#define SYS_MMAP $9
|
|
#define SYS_MUNMAP $11
|
|
#define SYS_EXIT $60
|
|
|
|
// From experiments:
|
|
#define FSIZEOFF 48
|
|
#define STATSIZE 144
|
|
|
|
// From Linux source:
|
|
#define RDONLY $00
|
|
#define PROT_READ $0x1
|
|
#define MAP_PRIVATE $0x02
|
|
#define STDIN $0
|
|
#define STDOUT $1
|
|
|
|
.global _start
|
|
.text
|
|
|
|
/* Details: */
|
|
/*
|
|
Remember: %rax(%rdi, %rsi, %rdx, %r10, %r8, %r9)
|
|
- Open a file (get its fd)
|
|
- int fd = open("filename", RDONLY)
|
|
- Get its filesize:
|
|
- fstat(fd, statstruct). 0 if ok. fsize at statstruct+48
|
|
- Then memory map it.
|
|
- void* vmemptr = mmap(vmemptr, fsize, PROT_READ, MAP_PRIVATE, fd, 0)
|
|
- Scan for newlines, print line.
|
|
- Keep going until done. Details at 11.
|
|
- Unmap memory
|
|
- munmap(vmemptr, filesize). 0 if ok.
|
|
- Exit
|
|
*/
|
|
|
|
.macro ERRCHECK code
|
|
cmpq $\code, %rax
|
|
je fs_error
|
|
.endm
|
|
|
|
/* Local stack notes:
|
|
0: int fd
|
|
4: void* vmemptr
|
|
12: void* head
|
|
20: void* lookahead
|
|
28: void* end
|
|
*/
|
|
_start:
|
|
// Open:
|
|
movq RDONLY, %rsi
|
|
// Filename ptr is on stack currently as argv[1]:
|
|
cmpq $1, (%rsp) // if argc is 1, default to stdin
|
|
jnz open_file
|
|
subq $36, %rsp // local stack
|
|
movl STDIN, (%rsp)
|
|
jmp fstat
|
|
|
|
open_file:
|
|
movq 16(%rsp), %rdi // argc(8), argv0(8) => rsp+16. filename
|
|
movq SYS_OPEN, %rax
|
|
syscall
|
|
ERRCHECK -1
|
|
subq $36, %rsp // local stack
|
|
movl %eax, (%rsp) // int fd = open(argv[1], RDONLY)
|
|
|
|
// fstat to get filesize
|
|
fstat:
|
|
movq $statstruct, %rsi
|
|
movl (%rsp), %edi // fd
|
|
movq SYS_FSTAT, %rax
|
|
syscall // fstat(fd, statstruct)
|
|
ERRCHECK -1
|
|
|
|
// mmap - don't forget to munmap.
|
|
mmap:
|
|
movq $0, %r9 // offset
|
|
movq (%rsp), %r8 // fd
|
|
movq MAP_PRIVATE, %r10
|
|
movq PROT_READ, %rdx
|
|
movq filesize, %rsi
|
|
movq (%rsp), %rdi // vmemptr
|
|
movq SYS_MMAP, %rax
|
|
syscall
|
|
ERRCHECK -1
|
|
movq %rax, 4(%rsp) // void* vmemptr = mmap(vmemptr, fsize, PROT_READ, MAP_PRIVATE, fd, 0)
|
|
|
|
/* Print lines */
|
|
movq %rax, 12(%rsp) // head = vmemptr
|
|
addq filesize, %rax
|
|
decq %rax
|
|
movq %rax, 28(%rsp) // end = vmemptr+filesize-1
|
|
scan_outer:
|
|
movq 12(%rsp), %rax
|
|
cmpq 28(%rsp), %rax
|
|
jge cleanup // if head >= end, done
|
|
movq %rax, %rbx // Using rbx as lookahead
|
|
scan_inner:
|
|
cmpq 28(%rsp), %rbx
|
|
jge writeline // if lookahead >= end, write the line.
|
|
cmpb $'\n, (%rbx)
|
|
jz writeline // if '\n'==*lookahead, write the line
|
|
incq %rbx
|
|
jmp scan_inner
|
|
writeline:
|
|
// write:
|
|
incq %rbx
|
|
movq %rbx, %rdx
|
|
subq 12(%rsp), %rdx // rdx <- lookahead-head
|
|
movq 12(%rsp), %rsi
|
|
movq STDOUT, %rdi
|
|
movq SYS_WRITE, %rax
|
|
syscall // write(stdout, head, lookahead-head)
|
|
safety:
|
|
movq %rbx, 12(%rsp) // head = lookahead.
|
|
jmp scan_outer
|
|
|
|
cleanup:
|
|
// munmap
|
|
movq filesize, %rsi
|
|
movq 4(%rsp), %rdi
|
|
movq SYS_MUNMAP, %rax
|
|
syscall // munmap(vmemptr, filesize)
|
|
cmpq $-1, %rax
|
|
je fs_error
|
|
// close
|
|
movl (%rsp), %edi
|
|
movq SYS_CLOSE, %rax
|
|
syscall // close(fd)
|
|
ERRCHECK -1
|
|
|
|
exit:
|
|
movq SYS_EXIT, %rax
|
|
xorq %rdi, %rdi // The exit code.
|
|
syscall
|
|
|
|
fs_error:
|
|
movq SYS_EXIT, %rax
|
|
movq $-1, %rdi
|
|
syscall // exit(-1)
|
|
|
|
.data
|
|
statstruct: // This struct is 144 bytes. Only want size (+48)
|
|
.zero FSIZEOFF
|
|
filesize: // 8 bytes.
|
|
.quad 0
|
|
.zero STATSIZE-FSIZEOFF+8
|