homepage/content/posts/m32.md

158 lines
5.1 KiB
Markdown
Raw Normal View History

2023-06-14 14:14:25 +02:00
---
title: "Compiling C programs using -m32 on Arch in 2023"
description: "Compiling C programs for 32bit on Arch in 2023"
date: 2023-06-14T12:32:52+02:00
author: wanderer - https://git.dotya.ml/wanderer
draft: false
toc: true
enableGitInfo: true
images:
tags:
- archlinux
- compilation
- 32bit
---
## Intro
> **Preliminary:** To be clear, this short post is not primarily concerned with
> *running* the 32bit programs, instead specifically *compiling C programs for
> 32bit (x86)*.
Compiling a `C` program for a 32bit architecture in 2023?
Well, one might still want to poke at reversing smaller address-space programs,
*even in 2023*, and contrary to the popular belief, there still exist pieces of
software not ported to 64bit and architectures in use that are 32bit. Whatever
the motivation, the *compilation* process might not be as straight-forward on
Arch as one would maybe expect, so this post shows how it can be done. Unless
specified otherwise, the `x86` architecture is assumed.
### Example program
> Just show the example program already!
Nothing fancy, just saying hi and printing the value of `esp`. All that is
needed is to compile this into a 32bit binary.
```c
/* 32ftw.c */
#include <stdio.h>
int main() {
printf("hey 32!\n");
register int e asm("esp");
printf("esp: 0x%08x\n", e);
return 0;
}
```
For reference, the`GCC` version used was `gcc (GCC) 13.1.1 20230429`.
## TL;DR
To compile a 32bit `C` program on
[64bit-only](https://wiki.archlinux.org/title/Frequently_asked_questions#What_architectures_does_Arch_support?)
Arch, additional packages (on top of compilers/linkers) are required. As of
2023-06-14 these are:
* `core/lib32-glibc`
* `core/libr32-gcc-libs`,
which are the GNU C library (could also use [musl libc](https://musl.libc.org/)
but that would probably necessitate compiler wrapping as GCC seems to prefer
the GNU versions), and the 32bit version of the GCC libraries, respectively.
### Installing deps and calling it a day
```sh
~ % sudo pacman -S lib32-glibc lib32-gcc-libs
resolving dependencies...
looking for conflicting packages...
Package (2) New Version Net Change
core/lib32-gcc-libs 13.1.1-1 113.12 MiB
core/lib32-glibc 2.37-3 18.06 MiB
Total Installed Size: 131.18 MiB
:: Proceed with installation? [Y/n]
```
## The longer version
If you ever needed to compile some `C` sources (such as the example listed
[here](#example-program)) on Arch into a 32 bit binary? You might have
encountered the following:
```sh
~ % gcc -o 32ftw -m32 32ftw.c && ./32ftw
In file included from /usr/include/features.h:515,
from /usr/include/bits/libc-header-start.h:33,
from /usr/include/stdio.h:27,
from 32ftw.c:2:
/usr/include/gnu/stubs.h:7:11: fatal error: gnu/stubs-32.h: No such file or directory
7 | # include <gnu/stubs-32.h>
| ^~~~~~~~~~~~~~~~
compilation terminated.
```
Alright, a quick search and [an answer on Arch
forums](https://bbs.archlinux.org/viewtopic.php?pid=1136063#p1136063) points to
a (spoiler: *partial*) solution: `lib32-glibc` is needed, so let's install it
```sh
~ % sudo pacman -S lib32-glibc
```
and try again:
```sh
~ % gcc -o 32ftw -m32 32ftw.c && ./32ftw
/usr/sbin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-linux-gnu/13.1.1/../../../libgcc_s.so.1 when searching for libgcc_s.so.1
/usr/sbin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-linux-gnu/13.1.1/../../../libgcc_s.so.1 when searching for libgcc_s.so.1
/usr/sbin/ld: skipping incompatible /usr/lib/libgcc_s.so.1 when searching for libgcc_s.so.1
/usr/sbin/ld: cannot find libgcc_s.so.1: No such file or directory
/usr/sbin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-linux-gnu/13.1.1/../../../libgcc_s.so.1 when searching for libgcc_s.so.1
/usr/sbin/ld: skipping incompatible /usr/lib/libgcc_s.so.1 when searching for libgcc_s.so.1
collect2: error: ld returned 1 exit status
```
> Oh no, it still refuses to work.
As is *somewhat* hinted in the linker's error message depicted above, the
problem can be rectified by installing the GCC libraries (the 32bit version, of
course), which in Arch's `core` repository lives under the name
`lib32-gcc-libs`:
```sh
~ % sudo pacman -S lib32-gcc-libs
```
Now the program can finally be compiled and run and we can see it's a 32bit
binary.
```sh
~ % gcc -o 32ftw -m32 32ftw.c && ./32ftw
hey 32!
esp: 0xff8d27f0
~ % file ./32ftw
32ftw: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=2ff0c8dce8f64db4960aa6aef6cd9936326e990d, for GNU/Linux 4.4.0, not stripped
~ % ldd ./32ftw
linux-gate.so.1 (0xf7f50000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7ce5000)
/lib/ld-linux.so.2 => /usr/lib/ld-linux.so.2 (0xf7f52000)
```
## Closing words
To sum up, compiling a `C` program for 32bit on contemporary Arch works fine
with just a handful of dependencies. In author's opinion, this could be
highlighted better in the Archwiki, but perhaps the target audience is so small
that it hasn't even been considered.
For a not-much-talking summary, check out [TL;DR's calling it a
day](#installing-deps-and-calling-it-a-day).