6

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

ELF の代わりに COFF を作ろうとすると、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 から Intel へのコンバーターが機能していません。

4

1 に答える 1

2

私は専門家ではありませんが、16 ビット GAS 互換のアセンブラはありません。

さらに、gcc は 8086 の 16 ビット コードを生成することを意図したものではありませんでした。Rask ポートは、オペランド サイズがデフォルトで 16 ビットであるため、16 ビット コードを生成します。したがって、次のような命令は、リアル モードで解釈さmov ax, 1234hれる asb8 34h 12hではなく as として発行されます (80386+ で実行している場合)。66 b8 34h 12hmov eax, xxxx1234h

アドレスモードも同様です。

問題は、これが単なるコードであることです。オブジェクト ファイル形式はまだ 32 ビット用であるため、最終的には v86 環境で使用するために 32 ビット ツールで使用することを意図しています。たとえば、ELF は 16 ビットの再配置をサポートしておらず、COFF もサポートしていません (nasm によると)。

そのため、GCC と GAS でさえ 16 ビット コードを生成し、比較的新しいオブジェクト形式しか出力しません。オブジェクト ファイルを指定して MZ または COM 実行可能ファイルを作成するすべてのツールは、これらの形式よりも前に作成されており、サポートしていません。DOS はとうの昔に使用されなくなったため、新しいフォーマットのサポートを追加する努力はまったく行われませんでした。


非常に長い回避策 (使用することを意図していません)

gcc をコンパイラとして使用するには、非常に難しい2 つの方法しかイメージできません。

  1. NASMに移植してみてください。NASM は、YASM よりもはるかに多くの出力ファイル形式をサポートしています (ここでも、古い 16 ビット形式は廃止されました)。

フラグを使用してソース ファイルをアセンブルし、-masm=intelIntel 構文を取得します。次に、GAS ドット ディレクティブを NASM ディレクティブに変換するツールが必要です。 これは手動でコーディングする必要があります。それらのほとんどは.globalXXXのような単純な置換ですが、有効なアドレスを変換し、未定義の関数GLOBAL XXXを追加する必要があります。EXTERN XXX

  1. 引っ越しは自分たちで。(IA16 アーキテクチャと DOS のスキルが必要です)

外部シンボルを使用してはならず、PIC コード (-fPICフラグ) と生のバイナリ (つまり、コードのみ) を生成してはなりません。使用する必要がある外部関数ごとに 1 つずつ、関数ポインターの構造体を定義します。

構造体 context_t
{
    int (*printf)(char* フォーマット, ...);
    ...
};
次に、へのポインタを宣言しcontext_tますcontext_t* ctx。代わりにprintf使用のような関数を使用する必要がある場合。ctx->printfコードをコンパイルします。

context_tここで、型の変数を定義し、そのポインターを初期化する C ソースを作成し、それをローダーと呼びます。次に、ローダーはバイナリ ファイルを読み取り、ctxポインターに割り当てられたスペースを見つけて変数のアドレスに設定しcontext_t、バイナリ ファイルをメモリ (セグメント境界) にロードして、far 呼び出しで実行する必要があります。

ファイル内のポインターの位置を見つける必要があります。GCC によって生成されたマップ ファイル (-Xlinker -Map=output.mapスイッチ) を使用するか、古い BIOS PCI 32 ビット サービスのような署名 ($PCI 署名) を使用してスキャンすることができます。GCC によって生成されたコードは他の制約を課す可能性があることに注意してください。ただし、PIC スイッチはこれを最小限に抑える必要があります。ローダーの後にバイナリ ファイルを追加して (MZ 形式を使用し、位置合わせに注意する場合は注意してください)、物事を簡素化できます。

于 2015-05-21T16:55:11.173 に答える