On this page:
wrap-x64-run-time
wrap-x64-boilerplate
8.10

3.3 2c Run-Time System

William J. Bowman <wjb@williamjbowman.com>

This library provides the run-time system for supporting the CPSC 411 languages that can only produce two’s complement integers.

procedure

(wrap-x64-run-time v)  string?

  v : string?
Wraps v, a string representing a sequence of x64 instructions in Intel syntax, with the CPSC 411 run-time system.

This run-time system prints a two’s complement integer to the standard output port, as an ASCII string.

Implementation detail: currently, does nothing, as wrap-x64-boilerplate actually installs the run-time system, so this function cannot be used on its own; wrap-x64-boilerplate must be called immediately after.

Currently only supports Linux and macOS.

Example:
> (wrap-x64-run-time "mov rax, 5")

"mov rax, 5"

procedure

(wrap-x64-boilerplate e)  string?

  e : string?
Wraps e, a string representing a sequence of x64 instructions in Intel syntax, with necessary boilerplate to compile via nasm.

Implementation detail: currently, installs the run-time system as well.

Currently only supports Linux and macOS.

Examples:
> (require racket/pretty)
> (pretty-display (wrap-x64-boilerplate "mov rax, 5"))

global start

section .text

start:

  mov rbp, rsp

  mov r15, done

mov rax, 5

  ; The result should be a number in RAX

  jmp done

; Convert RAX to a string, left in buffer msg

; The result should be a number in RAX

; build the string backwards, then reverse

done:

number_to_string:

  mov rdi, 0                   ; index into msg, starting at beginning

  mov r12, 10                   ; divide by 10; idiv requires register arg

  mov rsi, msg

  mov r15, 0                    ; clear r15 to store negative flag

  cmp rax, 0                    ; if negative

  js neg

loop:

  mov rdx, 0                    ; extend rax to rdx

  idiv r12                      ; signed divide RDX:RAX by r12, with result

                                ; stored in RAX ← Quotient, RDX ← Remainder.

  add rdx, 48                   ; convert digit to ASCII char

  mov BYTE [rsi + rdi], dl      ; mov char into msg

  inc rdi

  cmp rax, 0

  jne loop

  cmp r15, 0                    ; if number if negative, add - as final character

  jl add_minus

; rdi contains the length of the msg

; msg is in rsi

reverse_msg:

  mov rdx, rdi ; preserve the length for printing

  dec rdi      ; length -> final index

  mov r9, 0    ; first character

rev_loop:

  cmp rdi, r9

  jle print_msg

  ; Until rdi <= r9, swap [rsi + rdi] and [rsi + r9]

  ; Save last character into register, move first character

  mov r8b, BYTE [rsi + rdi]

  mov r10b, BYTE [rsi + r9]

  mov BYTE [rsi + rdi], r10b

  mov BYTE [rsi + r9], r8b

  inc r9

  dec rdi

  jmp rev_loop

print_msg:

  mov     rax, 1

  mov     rdi, 1                ; And I want it to write to stdout

                                ; The message pointer is in rsi

                                ; length in rdx

  syscall

  mov     rax, 60    ; I'm about to call the OS sys_exit function

  mov     rdi, 0                ; The exit code is 0

  syscall

neg:

  mov r15, -1

  imul rax, -1

  jmp loop

add_minus:

  mov BYTE [rsi + rdi], 45

  inc rdi

  jmp reverse_msg

section .bss

section .data

dummy: db 0 ; Mac isn't happy with an empty .data

len:   equ  19

msg:   times len db '0'