ソフトウェアOS固有の理由


77

特定のオペレーティングシステム用のプログラミング言語を使用して作成されたソフトウェアがそれらでのみ動作する理由の技術的な詳細を判断しようとしています。

バイナリは特定のプロセッサに固有であり、理解しているプロセッサ固有のマシン言語と、異なるプロセッサ間で異なる命令セットがあるため、バイナリは特定のプロセッサに固有であることを理解しています。しかし、オペレーティングシステムの特異性はどこから来るのでしょうか?以前はOSが提供するAPIであると想定していましたが、次の本でこの図を見ました。 図

オペレーティングシステム-内部構造と設計原則7th ed-W. Stallings(Pearson、2012)

ご覧のとおり、APIはオペレーティングシステムの一部として示されていません。

たとえば、次のコードを使用してCで簡単なプログラムを作成する場合:

#include<stdio.h>

main()
{
    printf("Hello World");

}

コンパイラはこれをコンパイルするときにOS固有のことを何ですか?


15
ウィンドウに印刷しますか?またはコンソール?またはグラフィックメモリに?そこにデータをどのように入れますか?Appleのprintfを見る] [+は、Mac OS 7とは静かに異なり、Mac OS Xとはまったく異なります(コンピューターの1つの「行」に固執するだけです)。

3
Mac OS 7用にそのコードを記述した場合、新しいウィンドウのテキストに表示されるからです。Apple] [+で行った場合、メモリの一部のセグメントに直接書き込むことになります。Mac OS Xでは、コンソールに書き出します。したがって、thatsは、ライブラリレイヤーによって処理される実行ハードウェアに基づいてコードを処理する3つの異なる記述方法です。

2
うん@StevenBurnap - en.wikipedia.org/wiki/Aztec_C

10
FFT関数は、再コンパイルすることなく、WindowsまたはLinux(同じCPU上)で正常に実行されます。しかし、結果をどのように表示しますか?もちろん、オペレーティングシステムAPIを使用します。(printfmsvcr90.dllと同じではないprintflibc.so.6とから)
user253751

9
APIが「オペレーティングシステムの一部ではない」場合でも、1つのOSから別のOSに移行する場合、APIは異なります。(もちろん、図によれば、「オペレーティングシステムの一部ではない」というフレーズが実際に意味するものの問題を提起します。)
Theodoros Chatzigiannakis 14

回答:


78

コードがCPUに固有である場合、OSにも固有である必要がある理由について説明します。これは実際、ここでの回答の多くが想定している興味深い質問です。

CPUセキュリティモデル

ほとんどのCPUアーキテクチャで実行される最初のプログラムは、内部リングまたはリング0と呼ばれる内部で実行されます。特定のCPUアーチがリングを実装する方法は異なりますが、ほとんどすべての最新のCPUには少なくとも2つの動作モードがあり、1つは特権があり、CPUが実行できる正当な操作を実行できる「ベアメタル」コードを実行し、もう1つは定義された安全な機能セットのみを実行できる、保護されていないコードを実行します。ただし、一部のCPUの粒度ははるかに高く、VMを安全に使用するには少なくとも1つまたは2つの追加のリングが必要です(多くの場合、負の番号のラベルが付いています)が、これはこの答えの範囲外です。

OSの出番

初期のシングルタスクOS

非常に初期のDOSおよび他の初期のシングルタスクベースのシステムでは、すべてのコードが内側のリングで実行され、実行したすべてのプログラムはコンピューター全体でフルパワーを発揮し、すべてのデータの消去やハードウェアの損傷を含む誤動作があれば文字通り何でもできる非常に古いディスプレイ画面で無効なディスプレイモードを設定するなどのいくつかの極端なケースでは、さらに悪いことに、これは単に悪意のないバグのあるコードによって引き起こされる可能性があります。

このコードは、プログラムをメモリにロードできるローダー(初期のバイナリ形式では非常に簡単)があり、コードがドライバーに依存せず、すべてのハードウェアアクセス自体を実装する限り、実際にはOSに依存しません。リング0で実行される限り、任意のOS。注:このような非常に単純なOSは、他のプログラムを実行するためだけに使用され、追加機能を提供しない場合通常モニターと呼ばれます。

最新のマルチタスクOS

UNIXNT始まるWindowsのバージョン、その他のさまざまなOS を含む最新のオペレーティングシステムは、この状況を改善することを決定しました。ユーザーは、マルチタスクなどの追加機能必要でした。または悪意のあるコード)がアプリケーションやマシンに無制限に損害を与えることはなくなりました。

これは上記のリングを使用して行われ、OSはリング0で実行される唯一の場所を取り、アプリケーションは外部の信頼できないリングで実行され、OSが許可した制限された操作セットのみを実行できます。

ただし、このユーティリティと保護の強化にはコストがかかり、プログラムはOSと連携して自分で実行することを許可されていないタスクを実行する必要があり、メモリにアクセスしてハードディスクを直接制御したり、任意に変更したりすることができなくなりましたデータではなく、OSにこれらのタスクを実行するように依頼して、操作の実行が許可されていることを確認し、それらに属していないファイルを変更せずに、操作が実際に有効であることも確認し、ハードウェアが未定義の状態のままになることはありません。

各OSは、OSが設計されたアーキテクチャに部分的に基づいて、部分的に問題のOSの設計と原則に基づいて、これらの保護の異なる実装を決定しました。たとえば、UNIXはマルチユーザー使用に適したマシンに焦点を当てますこのために利用できる機能は、Windowsがよりシンプルで、1人のユーザーでより遅いハードウェアで実行できるように設計されていました。ユーザースペースプログラムがOSと通信する方法は、X86ではARMまたはMIPSなどとまったく異なるため、対象となるハードウェアで作業する必要性に基づいてマルチプラットフォームOSに決定を行わせます。

これらのOS固有の対話は通常「システムコール」と呼ばれ、ユーザー空間プログラムがOSを介してハードウェアと完全に対話する方法を包含し、OSの機能に基づいて根本的に異なるため、システムコールを介して作業を行うプログラムはOS固有です。

プログラムローダー

システムコールに加えて、各OSは、プログラムを二次記憶媒体からメモリにロードするための異なるメソッドを提供します。特定のOSによってロードできるようにするには、プログラムはOSにその方法を説明する特別なヘッダーを含まなければなりませんロードして実行します。

このヘッダーは以前は非常にシンプルで、異なる形式のローダー書くのはほとんど簡単でしたが、動的リンクや弱い宣言などの高度な機能をサポートするelfなどの最新の形式では、OSがバイナリをロードしようとすることはほぼ不可能ですつまり、システムコールの非互換性がなくても、プログラムを実行可能な方法でramに配置することは非常に困難です。

図書館

プログラムがシステムコールを直接使用することはめったにありませんが、システムコールをプログラミング言語用のやや使いやすい形式でラップするライブラリを介してほぼ例外なく機能を獲得します。たとえば、CにはC標準ライブラリとLinuxおよび類似のwin32 lib Windows NT以上では、他のほとんどのプログラミング言語にも、システム機能を適切にラップする同様のライブラリがあります。

これらのライブラリは、上記のクロスプラットフォームの問題をある程度克服することもできます。SDL などの幅広いOSへの呼び出しを内部で管理しながら、アプリケーションに均一なプラットフォームを提供することを目的に設計されたライブラリがあります。プログラムはバイナリ互換ではなく、これらのライブラリを使用するプログラムはプラットフォーム間で共通のソースを持つことができるため、再コンパイルと同じくらい簡単に移植できます。

上記の例外

ここで述べたことすべてにもかかわらず、複数のオペレーティングシステムでプログラムを実行できないという制限を克服する試みがありました。いくつかの良い例は、win32プログラムローダー、バイナリ形式、およびWindowsプログラムをさまざまなUNIXで実行できるシステムライブラリの両方を正常にエミュレートしたWineプロジェクトです。いくつかのBSD UNIXオペレーティングシステムがLinuxソフトウェアを実行できるようにする互換性レイヤーもあります。もちろん、MacOS Xで古いMacOSソフトウェアを実行できるApple独自のシムもあります。

ただし、これらのプロジェクトは、膨大なレベルの手動開発努力によって機能します。2つのOSの違いに応じて、難易度はかなり小さいシムから他のOSのほぼ完全なエミュレーションにまで及ぶことがあります。


6
+1「ソフトウェアOS固有の理由」歴史だから。
ポールドレーパー14

2
CPUセキュリティモデルはx86から​​派生していますか?モデルが発明された理由と時期は?
n611x007 14

8
@naxaいいえ、それは長い間x86より前で、GE-645コンピューターでこのモデルを必要とする便利なマルチユーザータイムシェアリング機能を備えた最初のOSである1969年にMulticsに最初に部分的に実装されましたが、この実装は不完全で、依存していましたソフトウェアサポート、ハードウェアの最初の完全で安全な実装は、その後継であるHoneywell 6180にありました。これは完全にハードウェアベースであり、Multicsは相互干渉する機会なしに複数のユーザーからコードを実行できました。
バリティ14

@Valityまた、IBM LPARは〜1972 です。
エリオットフリッシュ14

@ElliottFrischうわー、それは印象的です。私はそれがそんなに早いことだとは知らなかった。その情報をありがとう。
バリティ14

48

ご覧のとおり、APIはオペレーティングシステムの一部として示されていません。

図を読みすぎていると思います。はい、OSはオペレーティングシステム関数の呼び出し方法のバイナリインターフェイスを指定し、実行可能ファイルのファイル形式も定義しますが、APIを提供します。これは、呼び出し可能な関数のカタログを提供するという意味です。 OSサービスを呼び出すアプリケーション。

この図は、オペレーティングシステムの関数は通常、単純なライブラリ呼び出しとは異なるメカニズムで呼び出されることを強調しようとしているだけだと思います。一般的なOSのほとんどは、プロセッサ割り込みを使用してOS機能にアクセスします。一般的な最新のオペレーティングシステムでは、ユーザープログラムがハードウェアに直接アクセスすることはできません。コンソールにキャラクターを書きたい場合は、OSに依頼してもらう必要があります。コンソールへの書き込みに使用されるシステムコールはOSごとに異なるため、ソフトウェアがOS固有である理由の1つの例があります。

printfはCランタイムライブラリの関数であり、一般的な実装ではかなり複雑な関数です。Googleを使用すると、複数のバージョンのソースをオンラインで見つけることができます。1つのガイド付きツアーについては、このページを参照してください。草の中では、1つ以上のシステムコールを行うことになりますが、それらのシステムコールはそれぞれホストオペレーティングシステムに固有のものです。


4
プログラムがすべて実行した場合、入力または出力なしで2つの数値を追加することでした。そのプログラムはまだOS固有ですか?
ポール14

2
OSは、ほとんどのハードウェア固有のものを抽象化レイヤーの背後に配置することを目的としています。ただし、OS自体(抽象化)は実装ごとに異なる場合があります。POSIXにはいくつかのOS(多かれ少なかれ)があり、おそらく他のOSもありますが、OS全体は抽象化の「見える」部分があまりにも異なります。前に述べたように、Windowsでは/ home / userを開くことができず、* N * XシステムではHKEY_LOCAL_MACHINE \ ...にアクセスできません。これらのシステムを互いに近づけるのに役立つ仮想(「エミュレーション」)ソフトウェアを作成できます、これは常に「OS POVから」の「サードパーティ」になります。
RobIII 14

16
@ポールはい。特に、実行可能ファイルへのパッケージ方法はOS固有です。
OrangeDog 14

4
@TimSeguine XP対7の例に同意しません。XPの場合と同じAPIが7に存在するようにするために、Microsoftが多くの作業を行っています。ここで起こったことは明らかに、プログラムが特定のAPIまたはコントラクトに対して実行するように設計されていることです。新しいOSは、同じAPI /契約を遵守しました。ただし、Windowsの場合、そのAPIは非常に独自仕様であるため、他のOSベンダーはそれをサポートしていません。それでも、7で実行されないプログラムの例はたくさんあります。
ArTs14年

3
@Paul:入出力を行わないプログラムは、空のプログラムであり、何もしないようにコンパイルする必要があります。
ベルギ14

14

コンパイラはこれをコンパイルするときにOS固有のことを何ですか?

恐らく。コンパイルおよびリンクプロセスのある時点で、コードはOS固有のバイナリに変換され、必要なライブラリとリンクされます。OSがプログラムをロードして実行を開始できるように、プログラムはオペレーティングシステムが予期する形式で保存する必要があります。さらに、標準ライブラリ関数を呼び出しています。printf()これは、オペレーティングシステムが提供するサービスの観点から実装されています。

ライブラリは、インターフェイス(オペレーティングシステムとハードウェアからの抽象化層)を提供します。これにより、プログラムを別のオペレーティングシステムまたはハードウェア用に再コンパイルできます。しかし、その抽象化はソースレベルに存在します。プログラムがコンパイルおよびリンクされると、特定のOSに固有のインターフェイスの特定の実装に接続されます。


12

いくつかの理由がありますが、非常に重要な理由の1つは、プログラムを構成する一連のバイトをメモリに読み込む方法をオペレーティングシステムが認識し、そのプログラムに対応するライブラリを見つけてメモリにロードする必要があることです。その後、プログラムコードの実行を開始します。これを行うために、OSの作成者はその一連のバイトの特定の形式を作成し、OSコードがプログラムの構造のさまざまな部分を探す場所を知るようにします。主要なオペレーティングシステムの作成者は異なるため、これらの形式は多くの場合、互いにほとんど関係がありません。特に、Windows実行可能形式は、ほとんどのUnixバリアントが使用するELF形式とほとんど共通点がありません。したがって、このロード、動的リンク、および実行コードはすべてOS固有である必要があります。

次に、各OSはハードウェアレイヤーと通信するための異なるライブラリセットを提供します。これらはあなたが言及したAPIであり、一般的には、より複雑でより具体的な呼び出しをOS自体の深さに変換しながら、開発者によりシンプルなインターフェースを提供するライブラリです。多くの場合、このレイヤーはかなり灰色で、新しい「OS」APIは古いAPI上に部分的または全体的に構築されます。たとえば、Windowsでは、Microsoftが長年にわたって作成した新しいAPIの多くは、元のWin32 APIの基本的なレイヤーです。

この例では発生しませんが、開発者が直面する大きな問題の1つは、GUIを表示するためのウィンドウマネージャーとのインターフェイスです。ウィンドウマネージャーが「OS」の一部であるかどうかは、OSだけでなくあなたの視点にも依存します。WindowsのGUIはOSとより深いレベルで統合され、LinuxおよびOS XのGUIはより直接的に分離されました。これは非常に重要です。なぜなら、今日多くの人々が「オペレーティングシステム」と呼ぶものは、多くのアプリケーションレベルのコンポーネントが含まれているため、教科書が説明する傾向よりもはるかに大きな怪物です。

最後に、厳密にはOSの問題ではありませんが、実行可能ファイル生成の重要な問題は、異なるマシンが異なるアセンブリ言語ターゲットを持っているため、実際に生成されるオブジェクトコードが異なる必要があることです。これは厳密には「OS」の問題ではなく、ハードウェアの問題ですが、ハードウェアプラットフォームごとに異なるビルドが必要になることを意味します。


2
ロードされたコードを保持するために必要な量を超えるごく少量のRAM(存在する場合)を使用して、より単純な実行可能形式をロードできることに注意する価値があるかもしれませんが、より複雑な形式では、場合によってはより大きなRAMフットプリントが必要になることがあります読み込み後でも。MS-DOSは、任意のセグメントのオフセット0x100から始まる連続バイトをRAMに読み込むだけで、最大63.75KのCOMファイルをロードし、CXに終了アドレスをロードし、そこにジャンプします。シングルパスコンパイルは、バックパッチなしで(フロッピーで有用)達成できました。
supercat 14

1
...コンパイラに各ルーチンにすべてのパッチポイントのリストを含めます。各パッチポイントには前のリストのアドレスが含まれ、最後のリストのアドレスはコードの最後に配置されます。OSはコードを生のバイトとしてロードするだけですが、コード内の小さなルーチンは、コードの主要部分を実行する前に必要なすべてのアドレスパッチを適用できます。
supercat 14

9

私の別の答えから:

初期のDOSマシンと、Microsoftの世界への本当の貢献は次のとおりです。

Autocadは、印刷可能な各プリンターのドライバーを作成する必要がありました。ロータス1-2-3も同様です。実際、ソフトウェアを印刷する場合は、独自のドライバーを作成する必要がありました。10台のプリンターと10個のプログラムがある場合、本質的に同じコードの100個の異なる部分を別々に独立して記述する必要がありました。

Windows 3.1が(GEMや他の多くの抽象化レイヤーとともに)達成しようとしたことは、プリンターの製造元がプリンター用に1つのドライバーを作成し、プログラマーがWindowsプリンタークラス用に1つのドライバーを作成したためです。

これで、10個のプログラムと10個のプリンターがあれば、20個のコードを書くだけで済みます。Microsoft側のコードは誰もが同じだったので、MSの例では、作業がほとんどありませんでした。

今では、プログラムはサポート対象として選択した10台のプリンターだけでなく、メーカーがWindows用のドライバーを提供しているすべてのプリンターに制限されていました。

そのため、OSはアプリケーションにサービスを提供するため、アプリケーションは冗長な作業を行う必要がありません。

サンプルCプログラムでは、文字をユーザーインターフェイスに表示するOS固有のリソースであるstdoutに文字を送信するprintfを使用します。プログラムは、ユーザーインターフェイスがどこにあるかを知る必要はありません-DOSでも、グラフィカルウィンドウでも、別のプログラムにパイプで接続し、別のプロセスへの入力として使用できます。

OSはこれらのリソースを提供するため、プログラマーはほとんど作業をせずにさらに多くのことを達成できます。

ただし、プログラムの起動さえも複雑です。OSは、実行可能ファイルの先頭に特定の情報が含まれていることを期待します。この情報は、OSに起動方法を指示し、場合によって(AndroidやiOSなどのより高度な環境) 「サンドボックス」-ユーザーやその他のアプリを不正なプログラムから保護するためのセキュリティ対策。

そのため、実行可能なマシンコードが同じであり、OSリソースが必要ない場合でも、Windows用にコンパイルされたプログラムは、まったく同じハードウェア上であっても、追加のエミュレーションまたは変換レイヤーがないOS Xオペレーティングシステムでは実行されません。

初期のDOSスタイルのオペレーティングシステムは、同じAPIをハードウェア(BIOS)に実装し、OSがハードウェアにフックされてサービスを提供するため、多くの場合、プログラムを共有できました。したがって、COMプログラム(一連のプロセッサ命令の単なるメモリイメージ)を作成してコンパイルした場合、CP / M、MS-DOS、および他のいくつかのオペレーティングシステムで実行できます。実際、最新のWindowsマシンでCOMプログラムを実行できます。他のオペレーティングシステムは同じBIOS APIフックを使用しないため、エミュレーションまたは変換レイヤーがなければ、COMプログラムはそれらで実行されません。EXEプログラムは、単なるプロセッサ命令よりも多くの構造を含むため、APIの問題とともに、プログラムをメモリにロードして実行する方法を理解していないマシンでは実行されません。


7

実際には、本当の答えは、ということであるならば、すべてのOSが同じ実行可能バイナリファイルのレイアウトを理解しました、そしてあなたのソフトウェア、その後、あなただけのOSは(のOSが提供しないもの)に提供することを(C標準ライブラリのように)標準化された機能に自分自身を制限してしまいます、実際には、どのOSでも実行できます。

もちろん、現実はそうではありません。EXEファイルは同じフォーマットを持っていないELFの両方が同じCPU用のバイナリコードが含まれているにもかかわらず、ファイル。*だから、各オペレーティング・システムは、すべてのファイル形式を解釈できるようにする必要があるだろう、と彼らは単にこれをしなかったにそして、彼らが後でそうする理由はありませんでした(ほぼ間違いなく、技術的な理由ではなく商業的な理由から)。

さらに、あなたのプログラムはおそらくCライブラリが方法を定義していないことを行う必要があります(ディレクトリの内容をリストするような単純なことでも)、そのような場合、すべてのOSはあなたの達成のために独自の機能を提供しますタスク。当然、使用する最小の共通分母がないことを意味します(その分母を自分で作成しない限り)。

したがって、原則として、それは完全に可能です。実際、WINEはLinux上でWindows実行可能ファイルを直接実行ます。
しかし、それは膨大な作業であり、(通常)商業的に不当です。

*注意:実行可能ファイルには、単なるバイナリコードよりも多くのことがあります。ありますトン、それはへの輸出機能何が必要どのくらいのスタックメモリ、ファイルが依存するライブラリどのようなオペレーティングシステムに伝える情報の、他のオペレーティングシステムは、関連するデバッグ情報を見つけるかもしれないことに依存してもよいライブラリは、「どのように必要に応じてメモリ内のファイルを再配置する」、例外処理を正しく機能させる方法など...など、このために誰もが同意する単一のフォーマットがあるかもしれませんが、そうではありません。


おもしろい事実:標準化されたposizバイナリ形式があり、OS間で実行できます。それはただ一般的に使用されていません。
マルチン

@Marcin:WindowsをOSであるとは思わないようです。(または、WindowsはPOSIXバイナリを実行できると言っていますか?!)私の答えの目的のために、POSIXは私が言及している種類の標準ではありません。POSIXのXはUnixを表します。WindowsがたまたまPOSIXサブシステムを持っている場合でも、Windowsなどで使用することを意図していませんでした。
Mehrdad 14

1.すべてのOSで実行することなく、複数のOSで何かを実行できます。2. NTはposixバイナリを実行できるため、Windows。
マルチン

1
@Marcin:(1)先ほど言ったように、POSIXのXはUNIXの略です。それは他のOSが従うことを意図した標準ではなく、様々なUnix間の共通点に到達するための試みでした。Unix OSには複数のフレーバーがあるという事実は、Unix 以外のオペレーティングシステムとの互換性に関して私がやろうとしていることとはまったく無関係です。(2)#2のリファレンスを提供できますか?
Mehrdad 14

1
@Mehrdad:Marcinは正しい。Windows SUA(Unixアプリケーション用サブシステム)はPOSIX準拠
MSalters 14

5

図には「ライブラリ」によって「オペレーティングシステム」層から分離された「アプリケーション」層があります。これは、「アプリケーション」と「OS」がお互いについて知る必要がないことを意味します。これは図の簡略化ですが、そうではありません。

問題は、「ライブラリ」には実際には3つの部分があるということです。実装、アプリケーションへのインターフェイス、OSへのインターフェイスです。原則として、最初の2つはOSに関する限り「ユニバーサル」にすることができます(スライスする場所に依存します)が、3番目の部分(OSへのインターフェース)は通常はできません。OSへのインターフェイスは、必然的にOS、OSが提供するAPI、パッケージ化メカニズム(Windows DLLで使用されるファイル形式など)に依存します。

「ライブラリ」は一般に単一のパッケージとして利用できるため、プログラムが使用する「ライブラリ」を選択すると、特定のOSにコミットします。これは、次の2つの方法のいずれかで発生します。a)プログラマーが事前に完全に選択し、ライブラリとアプリケーション間のバインディングをユニバーサルにすることができますが、ライブラリ自体はOSにバインドされます。またはb)プログラムを実行するときにライブラリが選択されるようにプログラマが設定しますが、プログラムとライブラリ間のバインディングメカニズム自体はOS依存です(WindowsのDLLメカニズムなど)。それぞれに長所と短所がありますが、どちらの方法でも事前に選択する必要があります。

さて、これはそれが不可能であることを意味しませんが、あなたは非常に賢明でなければなりません。この問題を解決するには、実行時にライブラリを選択するルートに移動する必要があり、OSに依存しないユニバーサルバインディングメカニズムを考え出す必要があります(したがって、それを維持する責任があります。より多くの作業)。時々それは価値があります。

する必要はありませんが、そうする努力をするなら、特定のプロセッサに縛られたくない可能性が高いので、仮想マシンを書いてコンパイルしますプログラムをプロセッサに依存しないコード形式に変換します。

今までに、あなたは私がどこへ行くのか気づいたはずです。Javaのような言語プラットフォームはまさにそれを行います。Javaランタイム(ライブラリ)は、Javaプログラムとライブラリ間のOS中立バインディング(Javaランタイムがプログラムを開いて実行する方法)を定義し、現在のOSに固有の実装を提供します。.NETは、MicrosoftがWindows以外には何も「ライブラリ」(ランタイム)を提供しないことを除いて、ある程度同じことを行います(ただし、他のものは-Monoを参照してください)。また、実際にはFlashも同じことを行いますが、ブラウザの範囲がより限定されます。

最後に、カスタムバインディングメカニズムなしで同じことを行う方法があります。従来のツールを使用できますが、ユーザーがOSを選択するまで、ライブラリへのバインド手順を延期します。それがまさにソースコードを配布するときに起こることです。ユーザーはプログラムを受け取り、実行準備ができたらプロセッサ(コンパイル)とOS(リンク)にバインドします。

それはすべて、レイヤーのスライス方法に依存します。一日の終わりには、特定のマシンコードを実行する特定のハードウェアで作成されたコンピューティングデバイスが常にあります。レイヤーは主に概念的なフレームワークとしてあります。


3

ソフトウェアは常にOS固有ではありません。Javaと以前のp-codeシステム(およびScummVMの両方)は、オペレーティングシステム間で移植可能なソフトウェアを可能にします。Infocom(ZorkおよびZ-machineのメーカー)は、別の仮想マシンに基づいたリレーショナルデータベースも持っていました。ただし、あるレベルでは、それらの抽象化でさえ、コンピューターで実行される実際の命令に変換する必要があります。


3
ただし、Javaは仮想マシン上で実行されますが、これはクロスOSではありません。各OSに異なるJVMバイナリを使用する必要があります
Izkata 14

3
@Izkata本当ですが、ソフトウェアを再コンパイルしません(JVMのみ)。また、私の最後の文を参照してください。しかし、Sunにはバイトコードを直接実行できるマイクロプロセッサがあったことを指摘します。
エリオットフリッシュ14

3
JavaはOSですが、通常はJavaとは考えられていません。JavaソフトウェアはJava OSに固有であり、ほとんどの「実際の」OS用のJava OSエミュレーターがあります。ただし、WINEを使用してLinux上でWindowsソフトウェアを実行するなど、任意のホストおよびターゲットOSで同じことを実行できます。
user253751 14

@immibisもっと具体的になります。Java Foundation Classes(JFC、Javaの標準ライブラリ)はフレームワークです。Java自体は言語です。JVMはOSに似ています。名前に「仮想マシン」があり、そこで実行されるコードの観点からは、OSと同様の機能を実行します。

1

あなたは言う

特定のオペレーティングシステム用のプログラミング言語を使用して作成されたソフトウェアは、それらでのみ動作します

ただし、例として挙げたプログラムは、多くのオペレーティングシステムで動作し、一部のベアメタル環境でも動作します。

ここで重要なことは、ソースコードとコンパイル済みバイナリの違いです。Cプログラミング言語は、ソース形式でOSに依存しないように特別に設計されています。これは、「コンソールへの印刷」などの解釈を実装者に任せることで行います。ただし、CはOS固有のものに準拠している場合があります(理由については他の回答を参照してください)。たとえば、PEまたはELF実行可能形式。


6
OPがソースコードではなくバイナリについて質問していることは明らかです。
カレブ14

0

他の人たちは技術的な詳細をよくカバーしてくれました。技術的な理由はあまりありませんが、UX / UIの側面について言及したいと思います。

一度書いて、どこでも気まずく感じる

すべてのオペレーティングシステムには、独自のユーザーインターフェイスAPIと設計標準があります。1つのプログラムに対して1つのユーザーインターフェイスを記述し、複数のオペレーティングシステムで実行することは可能ですが、そうすることで、プログラムがどこでも違和感を感じることがなくなります。適切なユーザーインターフェイスを作成するには、サポートされている各プラットフォームの詳細を調整する必要があります。

これらの多くは細かい部分ですが、間違っているとユーザーをイライラさせます。

  • WindowsとOSXでは、ダイアログのボタンの順序が異なることを確認してください。これを間違えると、ユーザーは筋肉の記憶によって間違ったボタンをクリックします。Windowsには、「OK」、「キャンセル」の順に並んでいます。OSXでは順序が入れ替わっており、do-itボタンのテキストは実行されるアクションの簡単な説明です:「キャンセル」、「ゴミ箱に移動」。
  • 「戻る」動作は、iOSとAndroidで異なります。iOSアプリケーションは、必要に応じて、通常は左上に独自の戻るボタンを描画します。Androidには、画面の回転に応じて、左下または右下に専用のボタンがあります。OSの戻るボタンが無視された場合、Androidへのクイックポートは正しく動作しません。
  • 運動量のスクロールは、iOS、OSX、およびAndroidで異なります。悲しいことに、ネイティブUIコードを作成していない場合、おそらく独自のスクロール動作を作成する必要があります。

技術的にあらゆる場所で実行される1つのUIコードベースを作成できる場合でも、サポートされているオペレーティングシステムごとに調整することをお勧めします。


-2

この時点で重要な違いは、コンパイラをリンカから分離することです。ほとんどの場合、コンパイラはほぼ同じ出力を生成します(違いは主にさまざまな#if WINDOWSs によるものです)。一方、リンカーは、プラットフォーム固有のものをすべて処理する必要があります-ライブラリのリンク、実行可能ファイルの構築など。

言い換えると、コンパイラは実際の実行可能なコードを生成し、CPUの命令とリソースを使用する必要があるため、CPUアーキテクチャをほとんど考慮します(.NETのILまたはJVMのバイトコードは仮想CPUの命令セットと見なされることに注意してください)このビューで)。これが、たとえばx86とのコードを別々にコンパイルする必要がある理由ですARM

一方、リンカーは、このすべての生データと命令を取得し、ローダー(最近はほとんど常にOS)が理解できる形式に設定するとともに、静的にリンクされたライブラリをリンクする必要があります(これには、動的リンク、メモリ割り当てなどに必要なコードも含まれます)。

つまり、コードを1回だけコンパイルしてLinuxとWindowsの両方で実行できるようにすることができますが、2回リンクして、2つの異なる実行可能ファイルを生成する必要があります。現在、実際には、多くの場合、コードでも許可を行う必要があります((プリ)コンパイラディレクティブが来る場所です)。言うまでもなく、人々はビルド中にコンパイルとリンクを単一のステップとして扱います(コンパイラー自体の部分をもう気にしないように)。

DOS時代のソフトウェアは、多くの場合、バイナリポータブルでしたが、DOSまたはUnixに対してではなく、ほとんどのIBMスタイルのPCに共通する特定の契約に対してもコンパイルされたことを理解する必要があります-今日のAPI呼び出しをオフロードしますソフトウェア割り込み。これは静的リンクを必要としませんでした。必要なレジスタを設定するだけで、たとえばint 13hグラフィック関数を呼び出すだけで、CPUは割り込みテーブルで宣言されたメモリポインタにジャンプしただけです。もちろん、ペダルから金属までのパフォーマンスを得るには、これらの方法をすべて自分で作成する必要があったため、練習はかなり複雑でしたが、基本的にOSを完全に回避することになりました。そしてもちろん、OS APIとの相互作用を常に必要とするものがあります-プログラムの終了です。ただし、利用可能な最も単純な形式(たとえば、COMDOSでは、ヘッダーがなく、指示だけがあります)、終了したくありませんでした-ラッキー!そしてもちろん、ランタイムでも適切な終了を処理できるので、同じ実行可能ファイルでUnix終了とDOS終了の両方のコードを作成し、実行時にどちらを使用するかを検出できます:)


これはで説明するだけでポイントを繰り返しているようだ。この、この昨日投稿した前の答え
ブヨ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.