这是我正在尝试的:
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转换器无法正常工作.
解决方法
此外,gcc从未打算生成8086 16位代码. Rask端口在这个意义上产生16位代码
操作数大小默认为16位.所以像mov ax,1234h这样的指令被发射为b8 34h 12h,而不是66 b8 34h 12h,这将是
在实模式下解释为mov eax,xxxx1234h(如果你在80386上运行)
地址模式也是如此.
问题是这只是代码,目标文件格式仍然是32位,因此它们最终会被32位工具用于
v86环境.
例如,ELF不支持16位重定位,也不支持COFF(根据nasm).
因此,即使GCC和GAS生成16位代码,它们也只输出相对较新的对象格式.
给定目标文件创建MZ或COM可执行文件的每个工具都是在这些格式之前创建的,并且不支持它们.
由于DOS很久以前就不再使用,因此没有花费任何精力来增加对新格式的支持.
很长的解决方法(不打算使用)
我只能用两种非常非常难的方式将gcc用作编译器.
>尝试移植到NASM. NASM支持的输出文件格式远远超过YASM(旧的16位格式已被删除).
使用-masm = intel标志汇编源文件以获取Intel语法.然后,您需要一个工具将GAS点指令转换为NASM指令.
这必须手动编码.其中大多数是简单的替换,如.global XXX到GLOBAL XXX,但你需要转换有效的地址和
为未定义的函数添加EXTERN XXX.
>自己做搬迁. (你需要熟练使用IA16架构和DOS)
您不得使用任何外部符号并生成PIC代码(-fPIC标志)和原始二进制(即只是代码).
定义一个函数指针结构,一个用于你需要使用的每个外部函数,例如
struct context_t { int (*printf)(char* format,...); ... };
然后声明一个指向context_t的指针,比如context_t * ctx;
如果你需要使用像printf这样的函数,请改用ctx-> printf.
编译代码.
现在创建一个C源,调用它加载器,定义一个context_t类型的变量并初始化它的指针.
然后加载器必须读取二进制文件,找到为ctx指针分配的空间并将其设置为其context_t变量的地址,然后
将二进制文件加载到内存中(在段边界处)并使用远程调用执行它.
你需要在文件中找到指针的位置,你可以使用GCC生成的地图文件(-Xlinker -Map = output.map开关)或使用签名像旧的BIOS PCI 32bit服务($PCI签名)并扫描它.请注意GCC生成的代码可能会施加其他约束,但PIC开关应尽量减少这种情况.您可以在加载器之后附加二进制文件(请注意,如果您使用MZ格式并注意对齐)并简化操作.