如何组装GAS组件并将其与Open Watcom C库链接?

我试图生成16位DOS可执行文件,但使用gcc编译器。 所以我使用古老的gcc-4.3 ia16端口。 我创建了我的构建的Docker镜像: https : //registry.hub.docker.com/u/ysangkok/ia16-gcc-rask

这是我正在尝试的:

host $ mkdir results host $ docker run -v $PWD/results:/results -it ysangkok/ia16-gcc-rask container $ cd results 

我没有包含头文件,导致gcc无法使用OpenWatcom的libc头文件。

 container $ echo 'main() { printf("lol"); }' > test.c 

我没有链接因为我没有16位binutils可用。 如果我构建一个目标文件,它没有正确标记为16位。

 container $ /trunk/build-ia16-master/prefix/bin/ia16-unknown-elf-gcc -S test.c 

现在我有这个汇编文件:

  .arch i8086,jumps .code16 .att_syntax prefix #NO_APP .section .rodata .LC0: .string "lol" .text .p2align 1 .global main .type main, @function main: pushw %bp movw %sp, %bp subw $4, %sp call __main movw $.LC0, %ax pushw %ax call printf addw $2, %sp movw %bp, %sp popw %bp ret .size main, .-main .ident "GCC: (GNU) 4.3.0 20070829 (experimental)" 

在容器外面,在主机中,我尝试用yasm组装它:

  % yasm -m x86 -p gas -f elf -o test.o test.s test.s:1: warning: directive `.arch' not recognized test.s:3: error: junk at end of line, first unrecognized character is `p' 

我注释掉了语法行,因为yasm不理解它,并再试一次,这次它成功了。

我测试了重定位符号:

  % objdump -r test.o test.o: file format elf32-i386 RELOCATION RECORDS FOR [.text]: OFFSET TYPE VALUE 00000007 R_386_PC16 __main 0000000a R_386_16 .rodata 0000000e R_386_PC16 printf 

可悲的是,他们是32位。 当我尝试在容器中进行链接时,它不起作用:

 root@1341f35c4590:/# cd ow/binl/ root@1341f35c4590:/ow/binl# WATCOM=/ow /ow/binl/wlink Open Watcom Linker Version 1.9 Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. Source code is available under the Sybase Open Watcom Public License. See http://www.openwatcom.org/ for details. Press CTRL/D to finish WLINK>system dos WLINK>file /results/test.o [ comment: i press control-d on the next line ] WLINK>loading object files Warning! W1080: file /results/test.o is a 32-bit object file Error! E2015: file /results/test.o(test.s): bad relocation type specified Error! E2015: file /results/test.o(test.s): bad relocation type specified Error! E2015: file /results/test.o(test.s): bad relocation type specified 

如果我尝试制作COFF而不是ELF,那么yasm甚至无法组装:

 root@1341f35c4590:/# cd ow/binl/ root@1341f35c4590:/ow/binl# WATCOM=/ow /ow/binl/wlink Open Watcom Linker Version 1.9 Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. Source code is available under the Sybase Open Watcom Public License. See http://www.openwatcom.org/ for details. Press CTRL/D to finish WLINK>system dos WLINK>file /results/test.o WLINK>loading object files Warning! W1080: file /results/test.o is a 32-bit object file Error! E2015: file /results/test.o(test.s): bad relocation type specified Error! E2015: file /results/test.o(test.s): bad relocation type specified Error! E2015: file /results/test.o(test.s): bad relocation type specified 

我知道yasm不支持16位,但也许有一个解决方法? 是否有兼容GAS的16位汇编程序? GAS-to-Intel转换器无法正常工作。

不是专家,但AFAIK没有16位GAS兼容的汇编程序。

此外,gcc从未打算生成8086 16位代码。 Rask端口产生16位代码,默认情况下操作数大小为16位。 所以像mov ax, 1234h这样的指令是以b8 34h 12h而不是66 b8 34h 12h mov eax, xxxx1234h在实模式下将被解释为mov eax, xxxx1234h (如果你在80386+上运行)

地址模式也是如此。

问题是这只是代码,目标文件格式仍然是32位,所以它们最终会被32位工具用于v86环境。 例如,ELF不支持16位重定位,也不支持COFF(根据nasm)。

因此,即使GCC和GAS生成16位代码,它们也只输出相对较新的对象格式。 给定目标文件创建MZ或COM可执行文件的每个工具都是在这些格式之前创建的,并且不支持它们。 由于DOS很久以前就不再使用,因此没有花费任何精力来增加对新格式的支持。


很长的解决方法(不打算使用)

我只能用两种非常非常难的方式将gcc用作编译器。

  1. 尝试移植到NASM。 NASM支持的输出文件格式远远超过YASM(旧的16位格式已被删除)。

使用-masm=intel标志汇编源文件以获取Intel语法。 然后,您需要一个工具将GAS点指令转换为NASM指令。 这必须手动编码 。 其中大多数是简单的替换,如.global XXX到GLOBAL XXX但您需要转换有效地址并为未定义的函数添加EXTERN XXX

  1. 自己做搬迁。 (你需要熟练掌握IA16架构和DOS)

您不得使用任何外部符号并生成PIC代码( -fPIC标志)和原始二进制(即只是代码)。 定义一个函数指针结构,一个用于你需要使用的每个外部函数,例如

 struct context_t
 {
     int(* printf)(char * format,...); 
     ...
 };

然后声明一个指向context_t的指针,比如context_t* ctx ; 如果你需要使用像printf这样的printf使用ctx->printf 。 编译代码。

现在创建一个C源,调用它加载器,定义一个context_t类型的变量并初始化它的指针。 然后,加载程序必须读取二进制文件,找到为ctx指针分配的空间并将其设置为其context_t变量的地址,然后将二进制文件加载到内存中(在段边界处)并使用远程调用执行它。

您需要在文件中找到指针的位置,您可以使用GCC生成的地图文件( -Xlinker -Map=output.map开关)或使用旧BIOS PCI 32bit服务($ PCI签名)等签名并扫描它。 请注意GCC生成的代码可能会施加其他约束,但PIC开关应尽量减少这种限制。 您可以在加载器之后附加二进制文件(请注意,如果您使用MZ格式并注意对齐)并简化操作。