Executables
Making a binary executable file from FreeBASIC source files.
Preamble:
A binary file is simply one in a binary (i.e. non-text) format:
On Windows, the file's extension must be one of a fixed set of executable file extensions, including '*.exe'.
On Unix systems, the file's "executable" flag must also be set.
FreeBASIC consists of fbc (the command line compiler/linker), the runtime libraries, and FreeBASIC header files for third-party libraries.
In order to produce executables, fbc uses the GNU binutils (assembler, linker). When compiling for architectures other than 32bit x86, fbc depends on gcc to generate assembly.
FreeBASIC provides the FreeBASIC compiler/linker program (fbc or fbc.exe), as well as the tools and libraries it uses:
Those include the DJGPP libraries used by FreeBASIC for DOS and the MinGW/GCC libraries used by FreeBASIC for Windows.
- The binary format means that the file's contents should not be transformed for platform-specific reasons (e.g. replacing newlines from \n to \r\n).
- Binary files are not necessarily executable, for example a library compiled to '*.dll' or '*.a' form is a binary but not an executable.
- Executable files are not necessarily binary, for example a script in text form can be made executable on Operating Systems.
An executable file is one which can be executed (it can be run on the command-line by writing the name of the file itself as the command).- Binary files are not necessarily executable, for example a library compiled to '*.dll' or '*.a' form is a binary but not an executable.
- Executable files are not necessarily binary, for example a script in text form can be made executable on Operating Systems.
On Windows, the file's extension must be one of a fixed set of executable file extensions, including '*.exe'.
On Unix systems, the file's "executable" flag must also be set.
FreeBASIC consists of fbc (the command line compiler/linker), the runtime libraries, and FreeBASIC header files for third-party libraries.
In order to produce executables, fbc uses the GNU binutils (assembler, linker). When compiling for architectures other than 32bit x86, fbc depends on gcc to generate assembly.
FreeBASIC provides the FreeBASIC compiler/linker program (fbc or fbc.exe), as well as the tools and libraries it uses:
- fbc is a command line program that takes FreeBASIC source/include files ('*.bas'/'*.bi') and object/library files ('*.o'/'*.a'), then compiles them into executables.
- fbc is typically invoked by Integrated Development Environments (IDEs) or text editors, from a terminal or command prompt, or through build-systems such as makefiles.
- fbc itself is not a graphical code editor or IDE!
By default, FreeBASIC programs are linked against various system and/or support libraries, depending on the platform.- fbc is typically invoked by Integrated Development Environments (IDEs) or text editors, from a terminal or command prompt, or through build-systems such as makefiles.
- fbc itself is not a graphical code editor or IDE!
Those include the DJGPP libraries used by FreeBASIC for DOS and the MinGW/GCC libraries used by FreeBASIC for Windows.
Compiling an executable, in general
fbc is a compiler that takes fbc source code and transforms it in to a file that can be loaded and executed (run) by the operating system.
fbc doesn't do this all on it's own. It uses some intermediate files and other tools to complete this transformation.
The "main" entry point of an executable
fbc doesn't do this all on it's own. It uses some intermediate files and other tools to complete this transformation.
The "main" entry point of an executable
An executable needs a starting point.
This starting point which we will call the "main" function or "main" entry point needs to be recorded in the executable so that when the executable file is loaded by the operating system, the operating system knows where to begin execution of the program.
By default, the "main" function or starting point will be the first line of the first basic source file on the command line:
There can be only one "main" function for an executable. It's not possible to have more than one "main" function.
This starting point which we will call the "main" function or "main" entry point needs to be recorded in the executable so that when the executable file is loaded by the operating system, the operating system knows where to begin execution of the program.
By default, the "main" function or starting point will be the first line of the first basic source file on the command line:
$ fbc program.bas module1.bas module2.bas
This default can be overridden with the '-m module' option to specify a main module that is not the first source file given on the command line:
"program" becomes the main module because it is first, and fbc will generate an implicit "main" function that will be executed first when the executable is loaded.
$ fbc -m program module1.bas module2.bas program.bas
If no other option is given that will affect the compile process, this "main" function is generated implicitly by fbc.
The "-m program" option tells fbc to use "program.bas" as the main module, even though "program.bas" is not listed first.
There can be only one "main" function for an executable. It's not possible to have more than one "main" function.
Compile process for an executable
When fbc compiles basic source code, it translates the source in to another format that can be used by other tools that eventually create an executable.
By default, fbc will use these other tools automatically:
By default, fbc will use these other tools automatically:
' .-------------------------------------. ' | COMPILER | ' '------.----------------------.-------' ' | GAS backend | GCC backend ' | | ' .------V-----. gcc .---V----. ' | ASM CODE |<-----------| C CODE | ' | .s or .asm | compiler | .c | ' '------.-----' '--------' ' | (G)AS assembler ' | ' .------V------. ' | OBJECT CODE | ' | .o or .obj |-------------. ' '------.------' | ' | (G)AR archiver | ' | | ' .-------V--------. | ' | STATIC LIBRARY | | ' | .a or .lib |---------->| ' '----------------' | (G)LD linker ' | ' |----------------------------. ' | | ' .----------V-----------. .-----------V-----------. ' | BINARY | | SHARED LIBRARY | ' | no extension or .exe | | .so or .dll or .dylib | ' '----------------------' '-----------------------' ' ' ' Extensions are Unix convention vs Windows (ld does .lib too nowadays). ' In the case of shared libs, the name for Mac deviates (.dylib).
To see all the steps that fbc uses, specify '-v' on the command line to see the steps.
For example, on win32:
For example, on win32:
$ fbc a.bas -v FreeBASIC Compiler - Version 1.08.0 (2021-01-24), built for win32 (32bit) Copyright (C) 2004-2021 The FreeBASIC development team. standalone target: win32, 486, 32bit backend: gas compiling: a.bas -o a.asm (main module) assembling: D:\fb.git\bin\win32\as.exe --32 --strip-local-absolute "a.asm" -o "a.o" linking: D:\fb.git\bin\win32\ld.exe -m i386pe -o "a.exe" -subsystem console "D:\fb.git\lib\win32\fbextra.x" --stack 1048576,1048576 -s -L "D:\fb.git\lib\win32" -L "." "D:\fb.git\lib\win32\crt2.o" "D:\fb.git\lib\win32\crtbegin.o" "D:\fb.git\lib\win32\fbrt0.o" "a.o" "-(" -lfb -lgcc -lmsvcrt -lkernel32 -luser32 -lmingw32 -lmingwex -lmoldname -lgcc_eh "-)" "D:\fb.git\lib\win32\crtend.o"
Tools:
- GNU assembler 64-bit backend (-gen gas64):
- GCC compiler backend (-gen gcc):
Options controlling compile / assemble / link stages
- [ fbc ] compiler translate *.bas in to *.asm or *.c files
- [ gcc ] compiler translate *.c files in to *.asm files
- [ as ] assembler translate *.asm files in to *.o object files
- [ ld ] linker join *.o files (and other files) in to executable files
- emscripten backend has other tools
- llvm backend has other tools
- GNU assembler 32-bit backend (-gen gas):- [ gcc ] compiler translate *.c files in to *.asm files
- [ as ] assembler translate *.asm files in to *.o object files
- [ ld ] linker join *.o files (and other files) in to executable files
- emscripten backend has other tools
- llvm backend has other tools
*.bas => [ fbc ] => *.asm compile (first stage) to assembly (-r or -rr, -R or -RR)
*.asm => [ as ] => *.o assemble to object file (-c, -C)
*.o => [ ld ] => *[.exe] link to executable
*.asm => [ as ] => *.o assemble to object file (-c, -C)
*.o => [ ld ] => *[.exe] link to executable
*.bas => [ fbc ] => *.asm compile (first stage) to assembly (-r or -rr, -R or -RR)
*.asm => [ as ] => *.o assemble to object file (-c, -C)
*.o => [ ld ] => *[.exe] link to executable
*.asm => [ as ] => *.o assemble to object file (-c, -C)
*.o => [ ld ] => *[.exe] link to executable
*.bas => [ fbc ] => *.c compile (first stage) to C (-r, -R)
*.c => [ gcc ] => *.asm compile (second stage) to assembly (-rr, -RR)
*.asm => [ as ] => *.o assemble to object file (-c, -C)
*.o => [ ld ] => *[.exe] link to executable
*.c => [ gcc ] => *.asm compile (second stage) to assembly (-rr, -RR)
*.asm => [ as ] => *.o assemble to object file (-c, -C)
*.o => [ ld ] => *[.exe] link to executable
There are a few options that can control what fbc does with the intermediate files and at what point the process may be stopped early.
-r, -rr, -c : stop the compile / assemble process sometime before the link stage
-rr : overrides overrides -c, -C
-r and -rr : behave the same if there is only one compile stage
-R and -RR : behave the same if there is only one compile stage
-r, -rr, -c : override the default behaviour of creating an implicit "main" entry point, and no "main" function is created by default.
To have a "main" entry point when using the -r, -rr, -c, options, then '-m module' option needs to be used to indicate which module should have an "main" function.
Note:-r, -rr, -c : stop the compile / assemble process sometime before the link stage
Compiler Option -r : compile up to first stage, keep file (*.asm/*.c), and stop
Compiler Option -rr : compile up to second stage, keep file (*.asm), and stop
Compiler Option -c : compile up to assembly stage, keep file (*.o), and stop
-R, -RR, -C : keep intermediate files at compile / assemble stages then continue to next stageCompiler Option -rr : compile up to second stage, keep file (*.asm), and stop
Compiler Option -c : compile up to assembly stage, keep file (*.o), and stop
Compiler Option -R : don't delete compile (first stage) intermediate file (*.asm/*.c)
Compiler Option -RR : don't delete compile (second stage) intermediate file (*.asm)
Compiler Option -C : don't delete assemble stage intermediate file (*.o)
-r : option overrides -rr, -RR, -c, -CCompiler Option -RR : don't delete compile (second stage) intermediate file (*.asm)
Compiler Option -C : don't delete assemble stage intermediate file (*.o)
-rr : overrides overrides -c, -C
-r and -rr : behave the same if there is only one compile stage
-R and -RR : behave the same if there is only one compile stage
-r, -rr, -c : override the default behaviour of creating an implicit "main" entry point, and no "main" function is created by default.
To have a "main" entry point when using the -r, -rr, -c, options, then '-m module' option needs to be used to indicate which module should have an "main" function.
Before fbc version 1.09.0, -gen gas64 generated a .a64 file extension for assembler (instead of .asm).
Execution order of the different modules
An executable program needs a "main" point of entry (in the main module user code).
fbc may or may not create an implicit main function, depending on options or method of building an executable.
The module constructors of modules run before main, the module destructors of modules run after main.
The module-level codes of other modules (than the main module) are put in implicit module constructors which are consequently executed before the module-level code of the main module.
But it would be good practice that module-level code only be in the main module.
More generally, all module constructors and module destructors should be noted with a big WARNING on their use. Because the corresponding code is run outside of user code, it's quite likely that fbc's error checking and some runtime facilities won't work as expected.
A high level description of the start-up framework:
fbc may or may not create an implicit main function, depending on options or method of building an executable.
The module constructors of modules run before main, the module destructors of modules run after main.
The module-level codes of other modules (than the main module) are put in implicit module constructors which are consequently executed before the module-level code of the main module.
But it would be good practice that module-level code only be in the main module.
More generally, all module constructors and module destructors should be noted with a big WARNING on their use. Because the corresponding code is run outside of user code, it's quite likely that fbc's error checking and some runtime facilities won't work as expected.
A high level description of the start-up framework:
- At compile time make arrays of addresses for all the module constructors and destructors.
- At link time, store the arrays in the executable.
- At run time, the start-up framework will:
- At link time, store the arrays in the executable.
- At run time, the start-up framework will:
- call all the module constructors in the array,
- call the main module user code,
- on exit (or error), call all the module destructors (usually, depends on how the program failed though).
- call the main module user code,
- on exit (or error), call all the module destructors (usually, depends on how the program failed though).
See also:
- fbc command-line
- Static Libraries
- Shared Libraries (DLLs)
- Profiling with fb's profiler
- Profiling for gmon/gprof
- Embed and Access binary Data in Executable
Back to Programmer's Guide