78 lines
2.5 KiB
Markdown
78 lines
2.5 KiB
Markdown
layout: post
|
|
title: "C headers in Asm"
|
|
subtitle: "Cleaning up the build chain"
|
|
tags: [osdev]
|
|
|
|
> **NOTE (2016-11-01)**
|
|
>
|
|
> Since people are apparently still finding this page four years later (yay! Cool URLs don't change!): I've since found a better and more correct way of doing this.
|
|
>
|
|
> If you're compiling using `gcc`, you can just name your assembly files (with includes and macros and stuff) `whatever.S` (capital S), and compile them right down to `whatever.o` as you normally would (using `gcc`, not `as`).
|
|
>
|
|
> GNU make also has a builtin rule that does this automatically... yeah...
|
|
>
|
|
> From this I've learned the following
|
|
>
|
|
> - Trust make. It's terribly powerful if you trust it to be.
|
|
> - GCC is not the GNU C Compiler. It's the GNU Compiler Collection.
|
|
|
|
Something that always annoyed me is how hard it is to synchronize constants
|
|
between assembly and c code. In assembler, you define a constant value as
|
|
|
|
:::nasm
|
|
EXACT_PI equ 3
|
|
|
|
and in c
|
|
|
|
:::c
|
|
#define EXACT_PI 3
|
|
|
|
As is usually the case with things that annoy me, there is of course a solution
|
|
to this, as I found out today. The solution is the c preprocessor.
|
|
|
|
Normally, when you run a c compiler, it makes multiple passes over your source
|
|
file. The first one or two times, it runs a pre-processor. The preprocessor
|
|
checks for things like _#include_ and _#define_ and replaces macros. The next
|
|
pass actually compiles the code. Then the compiler invokes a linker and so on.
|
|
|
|
What I found out today is that you can run only the preprocessor and it will
|
|
replace all the preprocessor code and ignore the rest. In other words, you can
|
|
use c preprocessor macros in assembler. Awesome!
|
|
|
|
So, how is this done?
|
|
Well, here's a minimal (non-working) example:
|
|
|
|
_myAsmFile.asm_
|
|
|
|
:::nasm
|
|
#include <header.h>
|
|
|
|
mov eax, EXACT_PI
|
|
|
|
_include/header.h_
|
|
|
|
:::c
|
|
#pragma once
|
|
|
|
#define EXACT_PI 3
|
|
|
|
#ifndef __ASSEMBLER__
|
|
// This is not evaluated if header.h is included from an assembly file.
|
|
#endif
|
|
|
|
This is compiled through:
|
|
|
|
:::bash
|
|
$ cpp -I include -x assembler-with-cpp myAsmFile.asm -o myAsmFile.s
|
|
$ nasm myAsmFile.s
|
|
|
|
The _-x_-flag tells the preprocessor what type of file the following input
|
|
files are. _assembler-with-cpp_ means _cpp_ will ignore everything but the
|
|
preprocessor commands.
|
|
|
|
An alternative to _cpp_ is _gcc -E_. Actually, this is often exactly the same
|
|
thing...
|
|
|
|
|
|
This is implemented in git commit [742f2348ec](https://github.com/thomasloven/os5/tree/742f2348ecc58eaa8239b06c666bd8c3c539c019).
|