x86-assembling, cross-compilation and C
Working in research often means moving code between my laptop and various workstations or servers. This constant migration comes with a familiar headache: managing dependencies and permissions. While I could use Docker containers or write code in Go, I started wondering - could I achieve this using plain C with minimal OS interaction?
I’m specifically interested in raw numerical simulations like Metropolis-Hastings samplers - algorithms that essentially just work with vectors of numbers. These are perfect candidates for stripped-down implementations that should, theoretically, run anywhere. The ideal scenario in my mind is straightforward: compile my C code, upload the binary to a server, and run it with a simple:
chmod +x simulation
./simulation
While cross-compilation from Linux to Windows is possible with GCC, macOS binaries remain a challenge. This got me thinking about the minimal requirements I actually need:
- Build dependencies under 10MB - no VMs or huge toolchains like MinGW
- Cross-platform binaries that might sacrifice some optimization for portability
- Simple compilation process for Windows/Linux deployment
- Basic debugging capabilities (GCC/GDB would suffice)
The SmallerC + YASM approach
SmallerC is a stripped-down C compiler that generates 32-bit instructions. It’s not a complete C90 implementation, but it covers enough ground for numerical computing. What makes it particularly useful is its ability to work with various assemblers - this is where YASM comes in, providing the cross-platform compilation capability we need.
After some exploration, I found an interesting solution: using a cross-compiler assembler. Specifically, the combination of SmallerC and YASM caught my attention.
Here’s how to set it up SmallerC:
- Clone the GitHub repository SmallerC, or download the ZIP source code. I’ll do it
~/.smlrcc, but you can use your favorite directory.
In order to create binary files in Windows, the files must be combined. Some of the compiler’s low-level instructions can cause anti-malware software to report false positives.
If you don’t trust the code, you can always read, check, and compile it yourself (just type
./configure && makein the root directory and that’s all).
- Set the environment variable
SMLRC. In Linux/macOS, you can do it by adding this at the end of~/.profile:
export SMLRC=~/.smlrcc/v0100
- There are three folders with the binaries
~/.smlrcc/v0100/binw,~/.smlrcc/v0100/binlor~/.smlrcc/v0100/binmin your systemPATH. For instance, in macOS you can do it by adding this in~/.profile:
export PATH="$PATH:~/.smlrcc/v0100/bin"
Then, we can install YASM:
- Windows users can download it directly or use MSYS2 (my preferred approach)
- On Debian/Ubuntu:
sudo apt install yasm - On macOS with MacPorts:
sudo port install yasm
Our first Cross-Hello World!
That’s all. Let’s test it with a simple Hello World sample.c:
#include <stdio.h>
int main(int argc, char** argv){
printf("Hello world!");
return 0;
}
Now we can generate binaries for each platform:
# Windows binary
smlrcc sample.c -win -o sample-win.exe
# Linux binary
smlrcc sample.c -Linux -o sample-lin
# macOS binary
smlrcc sample.c -macos -o sample-mac
The size differences compared to GCC (gcc -O2 -o GCC-sample-default sample.c) build are interesting:
$ ls -Alh | awk '{print $5, $9}'
357K GCC-sample-default
20K sample-lin
17K sample-mac
26K sample-win.exe
99 sample.c
Additional thoughts
After working with this setup, I’ve found both advantages and limitations worth considering:
- The good parts:
- The project has 6 years of development behind it, showing reasonable maturity
- Cross-platform compilation feels surprisingly straightforward
- Binaries are compact with minimal dependencies
- The codebase is well-written and comprehensible, making it fixable if needed
- The challenges:
-
It only supports a subset of C90. More details here
-
No integrated debugger (though GCC/GDB can fill this gap)
-
Not quite production-ready for commercial applications
-
May require code adjustments based on specific use cases as every user can have different experiences
-
For my research simulations, this approach has proven valuable. It’s not a universal solution, but for numerical computations that need to run across different platforms with minimal setup, it’s a practical alternative to heavier toolchains.
If you want to explore this setup yourself, here are the key resources:
- SmallerC Compiler:
- Binaries: Windows , Linux, MacOS
- Documentation
- YASM: Yasm Modular Assembler