问题
I am trying to produce 16-bit DOS executables, but using the gcc compiler. So I am using the ancient gcc-4.3 ia16 port. I made a Docker image of my build: https://registry.hub.docker.com/u/ysangkok/ia16-gcc-rask
Here's what I am trying:
host $ mkdir results
host $ docker run -v $PWD/results:/results -it ysangkok/ia16-gcc-rask
container $ cd results
I don't include the header, cause gcc can't use OpenWatcom's libc headers.
container $ echo 'main() { printf("lol"); }' > test.c
I don't link cause I don't have 16-bit binutils available. If I build an object file, it isn't correctly marked as 16-bit.
container $ /trunk/build-ia16-master/prefix/bin/ia16-unknown-elf-gcc -S test.c
Now I have this assembly file:
.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)"
Outside the container, in the host, I try to assemble it with 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'
I comment out the syntax line since yasm doesn't understand it, and try again, this time it succeeds.
I test the relocation symbols:
% 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
Sadly they are 32-bit. When I try and link anyway in the container, it doesn't work:
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
If I try and make a COFF instead of an ELF, yasm can't even assemble:
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
I know yasm doesn't support 16-bit, but maybe there is a workaround? Is there a GAS-compatible 16-bit assembler? The GAS-to-Intel converters are not working.
回答1:
I'm not an expert but AFAIK there are no 16 bit GAS compatible assemblers.
Furthermore gcc was never meant to produce 8086 16 bit code. The Rask port produce 16 bit code in the sense
that the operand size is 16 bit by default. So an instruction like mov ax, 1234h
is emitted as b8 34h 12h
rather than as 66 b8 34h 12h
which will be
interpreted as mov eax, xxxx1234h
in real mode (if you run on 80386+)
Same thing for the address mode.
The problem is that this is just the code, the object file formats are still for 32 bit, so they are meant to be used by 32 bit tools eventually for use in a v86 environment. ELF for example don't support 16 bit relocation, nor COFF does (according to nasm).
So even GCC and GAS produce 16 bit code they output only relatively new object format. Every tools that given an object file create a MZ or COM executable was created before these formats and don't support them. No efforts have been spent on adding support to new formats as DOS ceased to be used long time ago.
Very long Workarounds (not meant to be used)
I can only image two, very very hard, way to use gcc as a compiler.
- Try porting to NASM. NASM support far more output file format than YASM (again old 16 bit format have been dropped).
Assemble the source file with -masm=intel
flag to get Intel syntax. Then you need a tool to convert GAS dot directives to NASM directives.
This have to be coded manually. Most of them are simple substitutions like .global
XXX to GLOBAL XXX
but you need to convert effective addresses and
add EXTERN XXX
for undefined functions.
- Do the relocations yourself. (You need to be skilled with IA16 architecture and DOS)
You must not use any external symbol and produce PIC code (-fPIC
flag) and a raw binary (i.e. just code).
Define a struct of function pointers, one for each external function you need to use, something like
struct context_t { int (*printf)(char* format, ...); ... };Then declare a pointer to
context_t
, say context_t* ctx
;
If you need to use a function like printf
use ctx->printf
instead.
Compile the code.
Now create a C source, call it loader, that define a variable of type context_t
and initialize its pointers.
The loader then must read the binary file, locate the space allocated for the ctx
pointer and set it to the address of its context_t
variable, then
load the binary file in memory (at segment boundary) and execute it with a far call.
You need to find the position of the pointer in the file, you can use a map file generated by GCC (-Xlinker -Map=output.map
switch) or use a signature
like the old BIOS PCI 32bit service (the $PCI signature) and scan for it.
Beware that the code generated by GCC may impose other constraints, but the PIC switch should minimize this.
You can event append the binary file after the loader (beware if you use MZ format and mind the alignment) and simplify things.
来源:https://stackoverflow.com/questions/30191000/how-do-i-assemble-gas-assembly-and-link-it-with-the-open-watcom-c-library