File: ruler-linux-amd64.asm 1 ; The MIT License (MIT) 2 ; 3 ; Copyright (c) 2026 pacman64 4 ; 5 ; Permission is hereby granted, free of charge, to any person obtaining a copy 6 ; of this software and associated documentation files (the "Software"), to deal 7 ; in the Software without restriction, including without limitation the rights 8 ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 ; copies of the Software, and to permit persons to whom the Software is 10 ; furnished to do so, subject to the following conditions: 11 ; 12 ; The above copyright notice and this permission notice shall be included in 13 ; all copies or substantial portions of the Software. 14 ; 15 ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 ; SOFTWARE. 22 23 24 ; To compile this app for linux/amd64, use the commands 25 ; 26 ; nasm -f elf64 -o ruler-linux-amd64.o ruler-linux-amd64.asm 27 ; ld -n -s ruler-linux-amd64.o -o ruler 28 ; rm ruler-linux-amd64.o 29 30 31 ; ruler [width...] 32 ; 33 ; Emit a line with a ruler-like pattern, which helps check the width of output 34 ; lines right above it. If given a valid number, it's used as the ruler width, 35 ; or 80 is used as the default width. 36 37 38 stdout equ 1 39 sys_write equ 1 40 sys_exit equ 60 41 42 lf equ 10 ; line feed 43 44 section .rodata 45 46 one_length equ 2 ; each middle-dot is 2 bytes 47 48 ten: 49 db 0xc2, 0xb7, 0xc2, 0xb7, 0xc2, 0xb7, 0xc2, 0xb7 ; 4 middle-dots 50 db 0xe2, 0x95, 0xb5 ; 1 high half vertical bar 51 five_length equ $ - ten 52 db 0xc2, 0xb7, 0xc2, 0xb7, 0xc2, 0xb7, 0xc2, 0xb7 ; 4 middle-dots 53 db 0xe2, 0x94, 0x82 ; 1 fancy vertical bar, not the ASCII one 54 ten_length equ $ - ten 55 56 eol: db lf ; end of line 57 58 section .text 59 60 global _start 61 62 _start: 63 64 ; rcx = argc 65 pop rcx 66 67 ; just use the default ruler-width, if no arguments were given 68 cmp rcx, 1 69 mov rdx, 1 70 je bad_width 71 72 ; skip argv[0] 73 pop rbx 74 ; get argv[1] 75 pop rbx 76 77 ; an empty string fails to parse: if so, use the default ruler-width 78 mov al, [rbx] 79 cmp al, 0 80 je bad_width 81 82 mov rdx, 0 83 mov rax, 0 84 parse_width: 85 mov al, [rbx] 86 cmp al, 0 87 je good_width 88 89 cmp al, '0' 90 jl bad_width 91 cmp al, '9' 92 jg bad_width 93 94 imul rdx, 10 95 sub al, '0' 96 add rdx, rax 97 98 inc rbx 99 jmp parse_width 100 101 bad_width: 102 ; use the default ruler-width 103 mov rdx, 80 104 good_width: 105 106 ruler: 107 ; the number-parser code stores the result in `rdx`, but the loop doing 108 ; the writing uses `rcx` instead 109 mov rcx, rdx 110 111 ; empty rulers shouldn't even emit a single-byte line-feed 112 cmp rcx, 1 113 jl quit 114 115 write_tens: 116 ; for (; rcx >= 10; rcx -= 10) 117 next_ten: 118 cmp rcx, 10 119 jl write_trail 120 push rcx 121 ; write(stdout, ten, ten_length) 122 mov rax, sys_write 123 mov rdi, stdout 124 mov rsi, ten 125 mov rdx, ten_length 126 syscall 127 pop rcx 128 sub rcx, 10 129 jmp next_ten 130 131 write_trail: 132 cmp rcx, 5 133 jl write_ones 134 push rcx 135 ; write(stdout, ten, five_length) 136 mov rax, sys_write 137 mov rdi, stdout 138 mov rsi, ten 139 mov rdx, five_length 140 syscall 141 pop rcx 142 sub rcx, 5 143 144 write_ones: 145 imul rcx, rcx, one_length 146 ; write(stdout, ten, rdx = one_length * rcx) 147 mov rax, sys_write 148 mov rdi, stdout 149 mov rsi, ten 150 mov rdx, rcx 151 syscall 152 153 end_line: 154 ; write(stdout, eol, 1) 155 mov rax, sys_write 156 mov rdi, stdout 157 mov rsi, eol 158 mov rdx, 1 159 syscall 160 161 quit: 162 ; exit(0) 163 mov rax, sys_exit 164 mov rdi, 0 165 syscall