The following assembly code counter.asm
counts to 10^9, using a linux system call to print:
section .data
count dd 0 ; Define a 32-bit integer for the count
section .text
global _start
_start:
mov ecx, 1000000000 ; Set loop count to 10^9
loop_start:
add dword [count], 1 ; Increment the count
loop loop_start ; Decrement ECX and loop if not zero
; Preparing to print the count
mov eax, 4 ; System call number for sys_write
mov ebx, 1 ; File descriptor 1 is stdout
mov ecx, count ; Pointer to the count to print
mov edx, 4 ; Number of bytes to write
int 0x80 ; Call kernel
; Exit the program
mov eax, 1 ; System call number for sys_exit
xor ebx, ebx ; Exit code 0
int 0x80 ; Call kernel
$ nasm -f elf64 counter.asm -o counter.o # assemble
$ ld counter.o -o counter # link
$ ./counter | hexdp
0000000 ca00 3b9a
0000004
Note that 0x3b9aca00 == 1000000000. The output defaults to unicode symbols as seen below
Timing:
$ time ./counter
ʚ;
real 0m1.167s
user 0m1.167s
sys 0m0.000s
Check with debugger to confirm it's actually counting
$ gdb ./counter
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./counter...
(No debugging symbols found in ./counter)
(gdb) disassemble _start
Dump of assembler code for function _start:
0x0000000000401000 <+0>: mov $0x3b9aca00,%ecx
End of assembler dump.
(gdb) disassemble 0x0000000000401000,+32
Dump of assembler code from 0x401000 to 0x401020:
0x0000000000401000 <_start+0>: mov $0x3b9aca00,%ecx
0x0000000000401005 <loop_start+0>: addl $0x1,0x402000
0x000000000040100d <loop_start+8>: loop 0x401005 <loop_start>
0x000000000040100f <loop_start+10>: mov $0x4,%eax
0x0000000000401014 <loop_start+15>: mov $0x1,%ebx
0x0000000000401019 <loop_start+20>: mov $0x402000,%ecx
0x000000000040101e <loop_start+25>: mov $0x4,%edx
End of assembler dump.
We can see the first three lines load 0x3b9aca00 into ecx and then repeatedly loop until the count reaches the value in ecx, i.e. it's actually looping.