From c706eb91161ed2077f85ad2a771d0f4c69ef09c1 Mon Sep 17 00:00:00 2001 From: Arturs Artamonovs Date: Sat, 27 Sep 2025 09:23:22 +0100 Subject: add post on arm64 tiny binaries --- md/writeup/arm64_make_tiny_binary.md | 185 +++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 md/writeup/arm64_make_tiny_binary.md (limited to 'md/writeup') diff --git a/md/writeup/arm64_make_tiny_binary.md b/md/writeup/arm64_make_tiny_binary.md new file mode 100644 index 0000000..f757e87 --- /dev/null +++ b/md/writeup/arm64_make_tiny_binary.md @@ -0,0 +1,185 @@ +title: ARM64 make tiny binaries +keywords:raspi5,asm,c,kernel,arm64 + +# ARM64 make tiny binaries + + +## Intro + +This notes based on [Making C executable smaller](/writeup/making_c_executables_smaller.md). +Now time came to create version for ARM. One example using C and one example using assembler. +Examples printout hello world message and exit, nothing else. + +## Minimal C program + +Two minimal C programs one that using libc other that doesn't + +### Source code without libc + +___mainc.c___ +```c +char str[] = "Hello world\n"; +unsigned int str_len = 12; +void _start() { + //write + asm(\ + "mov x0, #1\n" + "mov x1, %0\n" + "mov x2, %1\n" + "mov w8, #64\n" + "svc #0\n" + : + :"r"(str),"r"(str_len) + ); + //exit + asm(\ + "mov x0, #0\n" /* status := 0 */ + "mov w8, #93\n" /* exit is syscall #1 */ + "svc #0\n" + ); +} + +``` + +Compiles with +```bash +gcc -Os -c mainc.c mainc.o +ld mainc.o -o mainc +``` + +### Source code with libc + +__mainc2.c__ +```c +#include +void _start() { + write(1,"Hello world\n",12); + exit(0); +} +``` + +Compiles with +```bash +gcc -Os -c mainc2.c mainc2.o +ld mainc2.o -lc -o mainc2 +``` + + +## Minimal Assembler program + +Both examples will work with raspberry pi 4 as such. One example for ARMv7 +and other for ARMv8 + +### Source code for ARMv7 + +__main7.S__ + +```c +.text +.global _start +_start: + mov r0, #1 + ldr r1, =message + ldr r2, =len + mov r7, #4 + swi 0 + + mov r7, #1 + swi 0 + +.data +message: + .asciz "hello world\n" +len = .-message +``` + + +```bash +arm-linux-gnueabi-gcc -Os -c main7.S main7.o +arm-linux-gnueabi-ld -s main7.o -o main7 +``` + +### Source code for ARMv8 + + +__main.S__ +```c +.data + +/* Data segment: define our message string and calculate its length. */ +helloworld: + .ascii "Hello, ARM64!\n" +helloworld_len = . - helloworld + +.text + +/* Our application's entry point. */ +.globl _start +_start: + /* syscall write(int fd, const void *buf, size_t count) */ + mov x0, #1 /* fd := STDOUT_FILENO */ + ldr x1, =helloworld /* buf := msg */ + ldr x2, =helloworld_len /* count := len */ + mov w8, #64 /* write is syscall #64 */ + svc #0 /* invoke syscall */ + + /* syscall exit(int status) */ + mov x0, #0 /* status := 0 */ + mov w8, #93 /* exit is syscall #1 */ + svc #0 + +``` + + +```bash +gcc -Os -c main.S -o main.o +ld main.o -o main +``` + +## Binary size before compression + +After all examples compiled lets compare sizes + +| Binary | Size, bytes | +|---|---| +| C, libc| 67976 | +| C, no libc | 66680 | +| Asm, ARMv7 | 432 | +| Asm, ARMv8 | 1152 | + +## Packing the binaries into self extracting archive + +Binaries are stripped with + +```bash +strip +``` + +Then compressed with +```bash +7z a -tGZip -mx=9 main.gz main > /dev/null +``` + +Then self unpacking header is added + +__unpack.header__ +```bash +a=/tmp/I;tail -n+2 $0|zcat>$a;chmod +x $a;$a;rm $a;exit +``` + +```bash +chmod a+x main +``` + +Now the binaries can run as regular executable. + +## Binary sizes of compression + +Lets compare sizes after packing up the binaries + +| Binary | Compressed size, bytes | Original size, bytes | Size of original | +|---|---|---|---| +| C, libc| 1049 | 67976 | 1.5% | +| C, no libc | 517 | 66680 | 0.7% | +| Asm, ARMv7 | 291 | 432 | 67% | +| Asm, ARMv8 | 250 | 1152 | 21% | \ No newline at end of file -- cgit v1.2.3