I am trying to include a header file containing a macro into my main assembly file, but the compilation fails.
Below is my main.S
file
#include "common.h"
BEGIN
mov $0x0E40, %ax
int $0x10
hlt
Below is my common.h
file :
.macro BEGIN
LOCAL after_locals
.code16
cli
ljmp $0, $1f
1:
xor %ax, %ax
/* We must zero %ds for any data access. */
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %bp
/* Automatically disables interrupts until the end of the next instruction. */
mov %ax, %ss
/* We should set SP because BIOS calls may depend on that. TODO confirm. */
mov %bp, %sp
/* Store the initial dl to load stage 2 later on. */
mov %dl, initial_dl
jmp after_locals
initial_dl: .byte 0
after_locals:
.endm
Both files are in same directory. When I do the compilation :
$ as --32 -o main.o main.S
main.S: Assembler messages:
main.S:2: Error: no such instruction: `begin'
What am I missing? I did a little research and got this answer in SO, but its not helpful. Please help.
$ as --32 -o main.o main.S
as
is just an assembler, it translates assembly source to object code. It does not run the C preprocessor which is supposed to expand #include
.
(#
is the comment character in GAS syntax for x86 so the line is treated as a comment if it's seen by the assembler instead of replaced by CPP)
What you can do:
gcc
to assemble, with appropriate file suffix (.S
or .sx
), it will run the C preprocessor before running the assembler.
-v
to see what commands gcc
is invoking.-x assembler-with-cpp source.asm
.-save-temps
. This will write a .s
file with the preprocessed source.as
, you can for example -Wa,--32
. However, it is better to use options which the compiler driver understands like -m32
or -m16
in the present case. The driver knows about such options, for example it will also cater for appropriate options when linking, provided you are linking with gcc -m32 ...
as noted below..include
assembler directive which is handled by the assembler itself, not the C preprocessor.Note: In case 1. adding include search paths by means of -I path
might not work as expected: The compiler driver (gcc
in this case) will add -I path
only to the assembler's command line if it knows that it's the GNU assembler. You can tell this when the compiler is configured by configure flag --with-gnu-as
.
Note: Similar applies to linking. You probably do not want to call the linker (ld
by hand) unless you're making a static executable or flat binary; use gcc
or g++
instead if you're making a normal executable to run on the host system. It will add many options needed for linking like multilib paths, search paths, etc. which you do not want to fiddle by hand.
(int $0x10
is a 16-bit BIOS call, though, which won't work under a modern mainstream OS, only DOS or a legacy BIOS bootloader.)