Lately, I have been toying the Microsoft Assembler (MASM), and solving small programming challenges in it to learn about it how works. I typically use the GNU AS assembler because its so portable across instruction sets, and open source.
MASM is really interesting because unlike GNU As, which is simply a target for gcc, MASM is from an era where programmers were the target user. To that end, MASM ships with a lot of interesting features designed to improve the experience for the user including an advanced macro system including control flow logic, a type system, macro's to build function stack frames, and call other functions. Sadly, with 64-bit assembly, some of the magic has been lost (.invoke macro abandoned).
Here is an example program I wrote with MASM to solve a Challenge to order digits in a number in reverse.
There is a UASM project that brings some of this to Linux, including support for (.invoke) macro calling functions with the SYS-V ABI.
Post your favorite assembly tools, your experiences with MASM, and what kind of Macro systems you use if any. Should I learn M4 to bake on top of GNU AS?
.CODE
option casemap:none
option prologue:PrologueDef
option epilogue:EpilogueDef
public maxpermute
;;
; @brief Permute the digits of the number such that number returned as digits
; in descending order
maxpermute proc n:qword
local digit_arr[10]:byte
; prologue automatically written
xor eax,eax
cmp rcx, 0
jz @out
; save
mov [RBP+24], rdi ; save in shadow of rdx
mov n, rcx ; save n in shadow space
; zero the digit count array (al=0 here already)
lea rdi, digit_arr
mov ecx, sizeof digit_arr
rep stosb
; Walk the number computing digits
mov rax, n
@@:
xor edx, edx ; zero edx
mov ecx, 10
div rcx ; edx contains next digit
inc BYTE PTR [digit_arr+rdx]
test rax, rax
jnz @B
; Process the digits in descending order
xor rax, rax ; accumulator
mov ecx, 9; offset to last digit
@outer:
movzx rdi,BYTE PTR [digit_arr +rcx] ; fetch digit count
@inner: ; apply 10*acc + digit transform , rdi times
test rdi, rdi
jz @continue_outer
mov r8, rax
shl r8, 3
lea rax, [rax*2]
add rax, r8
add rax, rcx
dec rdi
test rdi, rdi
jnz @inner
@continue_outer:
loop @outer
mov rdi, n
@out:
ret
maxpermute endp
END
Check out GLIBC, the standard libc implementation for GNU/Linux, or the easier to read, minimalist, alternative libc MUSL.
Bootlin, runs the Elixir Code Cross Referencer that lets you easily hop between files. For instance, Here is the code for printf in GLIBC.