diff --git a/Makefile b/Makefile
index 1e3bdb3..de95d29 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,13 @@
 AS=riscv64-unknown-elf-as
 LD=riscv64-unknown-elf-ld
 
-all: main.x
+all: calc.elf
 
 hello.elf: hello.o
 	$(LD) -m elf32lriscv $^ -o $@
 
-main.x: main.o exit.o
-	$(LD) -m elf32lriscv $^ -o main.x
+calc.elf: calc.o
+	$(LD) -m elf32lriscv -T link.ld $^ -o $@
 
 %.o : %.s
 	$(AS) -mabi=ilp32e -march=rv32ec $< -o $@
diff --git a/README.md b/README.md
index f604ebf..3fd9503 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,14 @@ Notes
 
     riscv64-unknown-elf-objdump -D main.o
 
+### List Symbols
+
+    riscv64-unknown-elf-nm calc.o
+
+### List segment info
+
+    readelf -l calc.elf
+
 Resources
 ---------
 
diff --git a/calc.s b/calc.s
new file mode 100644
index 0000000..2b783d9
--- /dev/null
+++ b/calc.s
@@ -0,0 +1,110 @@
+# RISC-V assembly program implementing a calculator.
+
+.org 0
+# Provide program starting address to linker
+.global _start
+
+/* newlib system calls */
+.set SYSEXIT,  93
+.set SYSWRITE, 64
+
+.section .rodata
+str: .ascii "Hello World!\n"
+     .set str_size, .-str
+str2: .ascii "regdump\n"
+      .set str2_size, .-str2
+
+
+.section .bss
+buf: .skip 20        # room for 20 byte string
+                     # x10: ABCDEFG\n is 23 chars
+
+.section .data
+buflen: .byte 0      # length of buf string
+
+
+.text
+_start:
+    li t1, 0
+    li t2, 5
+
+    # dummy test for jal instruction
+.L1:
+    jal x0, .L2
+.L2:
+    nop
+
+loop:
+    beq t1, t2, end
+
+    li t0, SYSWRITE     # "write" syscall
+    li a0, 1            # 1 = standard output (stdout)
+    la a1, str          # load address of hello string
+    li a2, str_size     # length of hello string
+    ecall               # invoke syscall to print the string
+    addi t1, t1, 1
+    j loop
+
+end:
+    # do some adding
+    li a0, 0x80000000   # 0.5
+    li a1, 1            # 1
+    li a2, 0x80000000   # 0.5
+    li a3, 1            # 1
+    jal add64
+    #add t1, a0, 0       # copy a0 to t0 as end with overwrite it
+    jal regdump
+
+    li t0, SYSEXIT      # "exit" syscall
+    add a0, x0, 0       # Use 0 return code
+    ecall               # invoke syscall to terminate the program
+
+# 64-bit integer addition
+#   arguments:
+#       a0: x lower 32 bits
+#       a1: x upper 32 bits
+#       a2: y lower 32 bits
+#       a3: y upper 32 bits
+#   return:
+#       a0: x+y lower 32 bits
+#       a1: x+y upper 32 bits
+#
+add64:
+    add  a0, a0, a2  # add lower 32 bits
+    add  t0, a1, a3  # add upper 32 bits
+    sltu t1, a0, a2  # if lower 32-bit sum < a2 then set t1=1 (carry bit)
+    add  a1, t0, t1  # upper 32 bits of answer (upper sum + carry bit)
+    ret
+
+
+# Print values of all registers (in hex)
+# write syscall uses t0, a0, a1, a2
+regdump:
+    addi sp, sp, -16 # allocate stack space
+    sw a0, 12(sp)    # save contents of a0
+    sw a1, 8(sp)     # save contents of a0
+    sw a2, 4(sp)     # save contents of a0
+    sw t0, 0(sp)     # save contents of a0
+
+    li t0, SYSWRITE     # "write" syscall
+    li a0, 1            # 1 = standard output (stdout)
+    la a1, str2         # load address of hello string
+    li a2, str2_size    # length of other string
+    ecall               # invoke syscall to print the string
+
+    # as a test load something into buf and print it
+    la a1, buf          # load address of buf into a1
+    li a0, 'h
+    sb a0, 0(a1)
+    li a0, '\n
+    sb a0, 1(a1)
+    li a2, 2            # length of buf
+
+    li t0, SYSWRITE     # "write" syscall
+    li a0, 1            # 1 = standard output (stdout)
+    # li a2, buflen       # length of hello string
+    ecall               # invoke syscall to print the string
+
+    addi sp, sp, 16   # deallocate stack space
+    ret
+
diff --git a/link.ld b/link.ld
new file mode 100644
index 0000000..4a3aaef
--- /dev/null
+++ b/link.ld
@@ -0,0 +1,15 @@
+OUTPUT_ARCH( "riscv" )
+
+ENTRY(_start)
+
+SECTIONS
+{
+  . = 0x0;
+  .text : { *(.text) }
+  /* Address warning: calc.elf has a LOAD segment with RWX permissions
+   * https://www.redhat.com/en/blog/linkers-warnings-about-executable-stacks-and-segments
+   */
+  . = ALIGN (CONSTANT (COMMONPAGESIZE));
+  .data : { *(.data) }
+  .bss : { *(.bss) }
+}