可执行文件
- 来源: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgExecutables
- 最后更新: 2024-05-01
从 FreeBASIC 源文件生成二进制可执行文件。
前言:
二进制文件只是一种二进制(即非文本)格式的文件:
二进制格式意味着文件内容不应因平台特定原因而被转换(例如,将换行符从 \n 替换为 \r\n)。
二进制文件不一定是可执行文件,例如编译为
'*.dll'或'*.a'形式的库是二进制文件,但不是可执行文件。可执行文件不一定是二进制文件,例如文本形式的脚本可以在操作系统上设置为可执行文件。
可执行文件是可以被执行的文件(可以通过在命令行中写入文件名本身作为命令来运行)。
在 Windows 上,文件扩展名必须是固定可执行文件扩展名集合之一,包括 '*.exe'。
在 Unix 系统上,文件的"可执行"标志也必须设置。
FreeBASIC 由 fbc(命令行编译器/链接器)、运行库和第三方库的 FreeBASIC 头文件组成。
为了生成可执行文件,fbc 使用 GNU binutils(汇编器、链接器)。当为 32 位 x86 以外的架构编译时,fbc 依赖 gcc 生成汇编代码。
FreeBASIC 提供 FreeBASIC 编译器/链接器程序(fbc 或 fbc.exe),以及它使用的工具和库:
fbc 是一个命令行程序,接受 FreeBASIC 源/包含文件(
'*.bas'/'*.bi')和目标/库文件('*.o'/'*.a'),然后将它们编译为可执行文件。fbc 通常由集成开发环境(IDE)或文本编辑器调用,从终端或命令提示符调用,或通过构建系统(如 makefile)调用。
fbc 本身不是图形化代码编辑器或 IDE!
默认情况下,FreeBASIC 程序与各种系统和/或支持库链接,具体取决于平台。
这些库包括 FreeBASIC 用于 DOS 的 DJGPP 库和 FreeBASIC 用于 Windows 的 MinGW/GCC 库。
编译可执行文件(概述)
fbc 是一个编译器,将 fbc 源代码转换为可被操作系统加载和执行(运行)的文件。
fbc 并不独立完成这一过程。它使用一些中间文件和其他工具来完成这种转换。
可执行文件的"main"入口点
可执行文件需要一个起始点。
这个起始点(我们称之为"main"函数或"main"入口点)需要记录在可执行文件中,以便操作系统在加载可执行文件时知道从哪里开始执行程序。
默认情况下,"main"函数或起始点将是命令行中第一个 basic 源文件的第一行:
$ fbc program.bas module1.bas module2.bas
"program" 成为主模块,因为它排在第一位,fbc 将生成一个隐式的"main"函数,该函数在加载可执行文件时首先执行。
可以使用 '-m module' 选项覆盖此默认行为,以指定不是命令行中第一个源文件的主模块:
$ fbc -m program module1.bas module2.bas program.bas
"-m program" 选项告诉 fbc 将 "program.bas" 用作主模块,即使 "program.bas" 未排在第一位。
如果没有其他影响编译过程的选项,这个"main"函数由 fbc 隐式生成。
一个可执行文件只能有一个"main"函数。不可能有多个"main"函数。
可执行文件的编译过程
当 fbc 编译 basic 源代码时,它将源代码转换为另一种格式,该格式可被其他工具使用,最终创建可执行文件。
默认情况下,fbc 会自动使用这些其他工具:
' .-------------------------------------.
' | 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).要查看 fbc 使用的所有步骤,请在命令行中指定 '-v' 以查看这些步骤。
例如,在 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"工具:
[ fbc ] 编译器将 _.bas 转换为 _.asm 或 *.c 文件
[ gcc ] 编译器将 _.c 文件转换为 _.asm 文件
[ as ] 汇编器将 _.asm 文件转换为 _.o 目标文件
[ ld ] 链接器将 *.o 文件(和其他文件)合并为可执行文件
emscripten 后端有其他工具
llvm 后端有其他工具
GNU 汇编器 32 位后端(-gen gas):
*.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- GNU 汇编器 64 位后端(-gen gas64):
*.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- GCC 编译器后端(-gen gcc):
*.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控制编译/汇编/链接阶段的选项
有几个选项可以控制 fbc 对中间文件的处理,以及在何处提前停止该过程。
-r, -rr, -c:在链接阶段之前的某个时间停止编译/汇编过程
编译器选项 -r:编译到第一阶段,保留文件(.asm/.c),然后停止
编译器选项 -rr:编译到第二阶段,保留文件(*.asm),然后停止
编译器选项 -c:编译到汇编阶段,保留文件(*.o),然后停止
-R, -RR, -C:保留编译/汇编阶段的中间文件,然后继续到下一阶段
编译器选项 -R:不删除编译(第一阶段)中间文件(.asm/.c)
编译器选项 -RR:不删除编译(第二阶段)中间文件(*.asm)
编译器选项 -C:不删除汇编阶段中间文件(*.o)
-r:选项覆盖 -rr、-RR、-c、-C
-rr:覆盖 -c、-C
-r 和 -rr:如果只有一个编译阶段,则行为相同
-R 和 -RR:如果只有一个编译阶段,则行为相同
-r、-rr、-c:覆盖创建隐式"main"入口点的默认行为,默认情况下不创建"main"函数。
在使用 -r、-rr、-c 选项时要有"main"入口点,需要使用 '-m module' 选项来指示哪个模块应有"main"函数。
注意:
在 fbc 版本 1.09.0 之前,-gen gas64 为汇编器生成 .a64 文件扩展名(而非 .asm)。
不同模块的执行顺序
可执行程序需要一个"main"入口点(在主模块用户代码中)。
fbc 可能会也可能不会创建隐式 main 函数,取决于选项或构建可执行文件的方法。
模块的模块构造函数在 main 之前运行,模块的模块析构函数在 main 之后运行。
其他模块(非主模块)的模块级代码被放入隐式模块构造函数中,因此在主模块的模块级代码之前执行。
但最佳实践是模块级代码只在主模块中。
更一般地说,所有模块构造函数和模块析构函数在使用时都应该注意重大警告。因为对应的代码在用户代码之外运行,fbc 的错误检查和一些运行时功能很可能无法按预期工作。
启动框架的高级描述:
在编译时,为所有模块构造函数和析构函数创建地址数组。
在链接时,将数组存储在可执行文件中。
在运行时,启动框架将:
调用数组中的所有模块构造函数,
调用主模块用户代码,
在退出(或错误)时,调用所有模块析构函数(通常如此,但取决于程序如何失败)。
另请参阅
返回 目录