In the last blog, we finished the program that prints “Hello World” 30 times on Aarch64 machine, now we are going to code the same program on X86_64 machine using assembly language.
Step 1: start with a basic hello world program
.text
.globl _start
_start:
movq $len,%rdx /* message length */
movq $msg,%rsi /* message location */
movq $1,%rdi /* file descriptor stdout */
movq $1,%rax /* syscall sys_write */
syscall
movq $0,%rdi /* exit status */
movq $60,%rax /* syscall sys_exit */
syscall
.section .data
msg: .ascii "Hello, world!: 0\n"
len = . - msg
Step 2: loop 30 times output
.text
.globl _start
_start:
movb $'0', %r12b
movq $min, %r10
loop:
movq %r10, %r9
movq $len,%rdx /* message length */
movq $msg,%rsi /* message location */
movq $msg+15, %r11
movb %r12b, (%r11)
movq $1,%rdi /* file descriptor stdout */
movq $1,%rax /* syscall sys_write */
syscall
inc %r12b
inc %r10
cmp $max, %r10
jne loop
movq $0,%rdi /* exit status */
movq $60,%rax /* syscall sys_exit */
syscall
.section .data
msg: .ascii "Hello, world!: 0\n"
len = . - msg
min = 0
max = 30
division = 10
Step 3: deal with the second digit output
Now the already looped the output 30 times, but the we have not dealt with second digit output, so the output is :

On X86_64 machine, getting reminder is a little different:
movq $0, %rdx /*initialize rdx to 0 for division*/
movq %r10, %rax /*store the r10 value into rax for division*/
div %r9 /*divide rax value by 10(r9)*/
movq %rax, %r14 /*store the rax value(quotient) into r14*/
movq %rdx, %r15 /*store the rdx value(remainder) int r15*/
After dividing, the quotient and remainder will be stored into rax and rdx.
Lab 5 on X86_64
.text
.globl _start
_start:
movq $min, %r10 /*store the min vlaue into r10 as a loop index*/
movq $division, %r9 /*store the division value(10) into r9*/
loop:
cmp %r9, %r10 /*compare r10(loop index) with 10*/
jl digit_1 /*if r10 is less than 10, go to the subroutine digit_1*/
jmp digit_2 /*if r10 is greater or equal to 10, go to the subroutine digit_2*/
digit_1:
movq %r10, %r15 /*store the r10 value into r15*/
add $'0', %r15 /*add '0' to r15 so the value will be ascii number character value*/
movq $msg+15, %r11 /*the digit location within string*/
movb %r15b, (%r11) /*store the digit at the location*/
jmp print /*go to the subroutine print*/
digit_2:
movq $0, %rdx /*initialize rdx to 0 for division*/
movq %r10, %rax /*store the r10 value into rax for division*/
div %r9 /*divide rax value by 10(r9)*/
movq %rax, %r14 /*store the rax value(quotient) into r14*/
movq %rdx, %r15 /*store the rdx value(remainder) int r15*/
add $'0', %r14 /*add '0' to r14 so the value will be ascii number character value*/
add $'0', %r15 /*add '0' to r15 so the value will be ascii number character value*/
movq $msg+14, %r11 /*the digit location within string*/
movb %r14b, (%r11) /*store the digit at the location*/
movq $msg+15, %r12 /*the digit loctaion within string*/
movb %r15b, (%r12) /*store the digit at the location*/
jmp print /*go to the subroutine print*/
print:
movq $len,%rdx /* message length */
movq $msg,%rsi /* message location */
movq $1,%rdi /* file descriptor stdout */
movq $1,%rax /* syscall sys_write */
syscall
inc %r12b
inc %r10 /*increment loop index*/
cmp $max, %r10 /*compare the max with r10*/
jne loop /*if the max value and the r10(loop index) value is not equal,*/
/* redo the loop subroutine*/
movq $0,%rdi /* exit status */
movq $60,%rax /* syscall sys_exit */
syscall
.section .data
msg: .ascii "Hello, world!: \n"
len = . - msg
min = 0
max = 30
division = 10
In X86 part, I encountered many seg faults. To deal with that, I tried to use gdb to deal with that. But unfortunately, the gdb barely gives me useful information.
I will write another blog to describe how to use gdb to debug assembly code.