Skip to content

Instantly share code, notes, and snippets.

@jamesdiacono
Last active October 16, 2024 15:37
Show Gist options
  • Save jamesdiacono/bc9337520727876e09bafaf98225019c to your computer and use it in GitHub Desktop.
Save jamesdiacono/bc9337520727876e09bafaf98225019c to your computer and use it in GitHub Desktop.
The DEC64 number type for Linux (x64 and ARM), MacOS (Intel and Silicon) and Android. Include these files alongside https://github.com/douglascrockford/DEC64.
#!/bin/sh
# Translates DEC64's Windows-compatible MASM on stdin to
# UNIX-compatible NASM on stdout. Not general purpose.
# 0. Use the UNIX calling convention.
# 1. Replace equ with %define.
# 2. Replace public with global.
# 3. Replace unary macro with %macro.
# 4. Replace nullary macro with %macro.
# 5. Replace endm with %endmacro.
# 6. Replace if with %if.
# 7. Replace endif with %endif.
# 8. Replace named with positional parameter.
# 9. Replace segment with section.
# 10. Replace qword with dq.
# 11. Remove execute segment.
# 12. Flatten nested index: [a][b] -> [a+b].
# 13. Remove extraneous suffix matter.
# 14. Remove extraneous suffix matter.
# 15. Remove title.
sed \
-E \
-e "s/^UNIX equ 0/%define UNIX 1/g" \
-e "s/^(\w+)\s+equ\s+(.+)/%define \1 \2/g" \
-e "s/^public /global /g" \
-e "s/^(\w+) macro function/%macro \1 1/g" \
-e "s/^(\w+) macro/%macro \1 0/g" \
-e "s/^ endm/ %endmacro/g" \
-e "s/^ if / %if /g" \
-e "s/^ endif/ %endif/g" \
-e "s/^ (call|jmp)\s+function/ \1 %1/g" \
-e "s/^dec64_data segment para read/dec64_code section .text/g" \
-e "/^dec64_data ends/d" \
-e "s/^ qword/ dq /g" \
-e "/^dec64_code segment para execute/d" \
-e "s/(ptr )?\[(.+?)\]\[(.+?)\]/[\2+\3]/g" \
-e "/^dec64_code ends/d" \
-e "/^ end\b/d" \
-e "/^title /d"
#!/bin/bash
# This script builds and runs the DEC64 tests for an ARM64 Android device. It
# takes no arguments.
# DEC64's ARM source must be tweaked slightly to make it compatible with
# the Android NDK's clang:
# 0. Comments start with a double slash, not a semicolon.
# 1. The global directive, like all directives, is preceeded by a period.
# 2. The area directive is not supported. We do, however, align.
# 3. Labels must be suffixed with a colon.
# 4. An 8 byte constant is declared with .quad rather than dcq.
# 5. When shifting an address offset, an extra comma is required.
# 6. The end directive is unnecessary.
sed \
-E \
-e "s_;_//_g" \
-e "s/global ([a-z0-9_]+) \\[func\\]/.global \1/g" \
-e "s/area dec64, align=8, code, readonly/.align 8/g" \
-e "s/^([a-z0-9_]+)/\1:/g" \
-e "s/dcq/.quad/g" \
-e "s/x([0-9]) lsl 3/x\1, lsl 3/g" \
-e "/ end/d" \
<dec64.s \
>dec64.android.s \
|| exit
build_and_run() {
# Compile, assemble and link a source file into a binary executable, then
# transfer and run that executable on a connected Android device.
src=$1
bin=$2
# The tests shift negative integers on purpose, so we suppress that warning.
"NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android32-clang" \
-Wno-shift-negative-value \
-o $bin \
dec64_string.c \
dec64_math.c \
dec64.android.s \
$src \
&& adb push ./$bin /data/local/tmp/$bin \
&& adb shell /data/local/tmp/$bin
}
build_and_run dec64_test.c dec64_test \
&& build_and_run dec64_string_test.c dec64_string_test \
&& build_and_run dec64_math_test.c dec64_math_test \
|| exit
# This script has been tested on a Samsung A52 5G device running Android 12,
# using the Android NDK r25b.
#!/bin/sh
# This script builds and runs the DEC64 tests for an x64 machine running MacOS
# (Darwin).
./masm_to_nasm.sh <dec64.asm >dec64.nasm || exit
# Assemble dec64.o. We prefix the function names with an underscore, because
# that is what clang expects.
nasm -f macho64 --prefix _ dec64.nasm || exit
build_and_run() {
# Compile, assemble and link a source file into a binary executable, then run
# it.
# We opt out of creating a position independent executable (a PIE), because we
# depend on absolute addressing. Without passing the linker the -no_pie flag,
# we get a warning like
# PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in
# code signed PIE, but used in pack_increase from dec64.o.
# because of lines in dec64.nasm like
# mov r10, [r10+r9*8]
# The tests shift negative integers on purpose, so we suppress that warning.
src=$1
bin=$2
clang \
-Wl,-no_pie \
-Wno-shift-negative-value \
-o $bin \
dec64_string.c \
dec64_math.c \
dec64.o \
$src \
&& ./$bin
}
# Build and run each test.
build_and_run dec64_test.c dec64_test \
&& build_and_run dec64_string_test.c dec64_string_test \
&& build_and_run dec64_math_test.c dec64_math_test \
|| exit
# This script has been tested on MacOS 11.4 (Big Sur), using NASM
# v2.15.05 and clang 13.0.0.
#!/bin/bash
# This script builds and runs the DEC64 tests for a Macintosh with an Apple
# Silicon processor. It takes no arguments.
# DEC64's ARM source must be tweaked slightly to make it compatible with clang:
# 0. Comments start with a double slash, not a semicolon.
# 1. The global directive, like all directives, is preceeded by a period.
# 2. The area directive is not supported. We do, however, align.
# 3. Labels must be suffixed with a colon.
# 4. An 8 byte constant is declared with .quad rather than dcq.
# 5. When shifting an address offset, an extra comma is required.
# 6. The end directive is unnecessary.
# 7. The names of entrypoints require a leading underscore to link correctly.
sed \
-E \
-e "s_;_//_g" \
-e "s/global ([a-z0-9_]+) \\[func\\]/.global \1/g" \
-e "s/area dec64, align=8, code, readonly/.align 8/g" \
-e "s/^([a-z0-9_]+)/\1:/g" \
-e "s/dcq/.quad/g" \
-e "s/x([0-9]) lsl 3/x\1, lsl 3/g" \
-e "/ end/d" \
-e "s/dec64_/_dec64_/g" \
<dec64.s \
>dec64.silicon.s \
|| exit
build_and_run() {
# Compile, assemble and link a source file into a binary executable, then
# run it.
src=$1
bin=$2
# The tests shift negative integers on purpose, so we suppress that warning.
clang \
-Wno-shift-negative-value \
-o $bin \
dec64.silicon.s \
dec64_string.c \
dec64_math.c \
$src \
&& ./$bin
}
build_and_run dec64_test.c dec64_test \
&& build_and_run dec64_string_test.c dec64_string_test \
&& build_and_run dec64_math_test.c dec64_math_test \
|| exit
# This script has been tested on a 2021 MacBook Pro with an M1 Pro processor.
#!/bin/bash
# This script builds and runs the DEC64 tests for Linux running on a 64-bit
# ARM processor.
# DEC64's ARM source must be tweaked slightly to make it compatible with gcc:
# 0. Comments start with a double slash, not a semicolon.
# 1. The global directive, like all directives, is preceeded by a period.
# 2. The area directive is not supported. We do, however, align.
# 3. Labels must be suffixed with a colon.
# 4. An 8 byte constant is declared with .quad rather than dcq.
# 5. When shifting an address offset, an extra comma is required.
# 6. The end directive is unnecessary.
sed \
-E \
-e "s_;_//_g" \
-e "s/global ([a-z0-9_]+) \\[func\\]/.global \1/g" \
-e "s/area dec64, align=8, code, readonly/.align 8/g" \
-e "s/^([a-z0-9_]+)/\1:/g" \
-e "s/dcq/.quad/g" \
-e "s/x([0-9]) lsl 3/x\1, lsl 3/g" \
-e "/ end/d" \
<dec64.s \
>dec64.linux.s \
|| exit
build_and_run() {
# Compile, assemble and link a source file into a binary executable, then
# run it.
src=$1
bin=$2
gcc \
-o $bin \
dec64.linux.s \
dec64_string.c \
dec64_math.c \
$src \
&& ./$bin
}
build_and_run dec64_test.c dec64_test \
&& build_and_run dec64_string_test.c dec64_string_test \
&& build_and_run dec64_math_test.c dec64_math_test \
|| exit
# This script has been tested on Debian 12 (Bookworm) with gcc v12.2.0.
#!/bin/sh
# This script builds and runs the DEC64 tests for an x64 machine running Linux.
./masm_to_nasm.sh <dec64.asm >dec64.nasm || exit
# Assemble dec64.o.
nasm -f elf64 dec64.nasm || exit
build_and_run() {
# Compile, assemble and link a source file into a binary executable, then
# run it.
# We opt out of creating a position independent executable (a PIE), because we
# depend on absolute addressing. Without passing the the -no-pie flag, we get a
# warning like
# /usr/bin/ld: dec64.o: warning: relocation in read-only section `.text'
# /usr/bin/ld: warning: creating DT_TEXTREL in a PIE
# because of lines in dec64.nasm like
# mov r10, [r10+r9*8]
# We explicitly disable an executable stack to avoid a warning like
# /usr/bin/ld: warning: dec64.o: missing .note.GNU-stack section implies executable stack
src=$1
bin=$2
gcc \
-no-pie \
-z noexecstack \
-o $bin \
dec64_string.c \
dec64_math.c \
dec64.o \
$src \
&& ./$bin
}
# Build and run the tests.
build_and_run dec64_test.c dec64_test \
&& build_and_run dec64_string_test.c dec64_string_test \
&& build_and_run dec64_math_test.c dec64_math_test \
|| exit
# This script has been tested on Debian GNU/Linux 12 (Bookworm), using NASM
# v2.16.01 and gcc v12.2.0.
@Lovingleo
Copy link

DT_TEXTREL in a PIE

@jamesdiacono
Copy link
Author

jamesdiacono commented Aug 30, 2024

From test_linux_x64.sh:

# We opt out of creating a position independent executable (a PIE), because we
# depend on absolute addressing. Without passing the the -no-pie flag, we get a
# warning like

#   /usr/bin/ld: dec64.o: warning: relocation in read-only section `.text'
#   /usr/bin/ld: warning: creating DT_TEXTREL in a PIE

# because of lines in dec64.nasm like

#   mov     r10, [r10+r9*8]

@newbie-02
Copy link

hello,

duplicate to [ DEC64, nasm version still valid?
#35 ](douglascrockford/DEC64#35 (comment))

Is the 'nasm' version for linux supposed / tested to work with actual systems?
'gcc (Debian 13.3.0-5) 13.3.0'

I'm not an expert, 'me bad' is always an option, get compiler warnings about:

/usr/bin/ld: warning: dec64.o: missing .note.GNU-stack section implies executable stack
/usr/bin/ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker

And dec64_test.c produces 263 fails, starting with:

FAIL abs: nan
a                      nan
?     -36028797018963968 nan
=                      nan

FAIL abs: nonnan
a                      nan
?     -36028797018963968 nan
=                      nan

pass abs: zero
a                      0
=                      0

TIA for any hints :-)

@jamesdiacono
Copy link
Author

jamesdiacono commented Oct 15, 2024

From test_linux_x64.sh:

# This script has been tested on Debian GNU/Linux 11 (Bullseye), using NASM
# v2.15.05 and gcc v10.2.1.

Would you care to investigate?

@newbie-02
Copy link

newbie-02 commented Oct 15, 2024 via email

@jamesdiacono
Copy link
Author

jamesdiacono commented Oct 15, 2024

Thanks. Note that test_linux_x64.sh only supports the x64 architecture (and I do not currently have an x64 machine on hand to test with). If you are running Linux on an ARM processor, you should assemble dec64.s rather than dec64.nasm (if dec64.s doesn't assemble cleanly, refer to test_android.sh or test_darwin_silicon.sh for guidance).

@jamesdiacono
Copy link
Author

I have just added test_linux_arm.sh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment