アプリ版:「スタンプのみでお礼する」機能のリリースについて

C言語で書いてコンパイルしたプログラムで、実行中に関数のバイトコードのサイズを調べる手段はありますか?今、鋳型となる関数を用意して、それを別のメモリ上にコピーして実行させることを考えています。そのとき、関数をコピーするために関数のメモリ上でのサイズが必要です。OSはUbuntuを使っており、コンパイラはgccです。可能なら他の環境でも動く方法が知りたいです。

シンボルテーブルを解析する方法はどうかと思い調べたのですが、情報が乏しくnmコマンドの使い方程度しか見つかりませんでした。なにかいい方法をご存知でしたら力をお貸しいただけると幸いです。

質問者からの補足コメント

  • Tacosanさんのご指摘の通り、説明不足でした。

    プロセッサはIntel x64を想定しています。
    「鋳型となる関数を用意して、それを別のメモリ上にコピーして実行させる」ことは、並列計算に興味を持ち、複数のスレッドが干渉し合わないようにスレッドの数だけ関数をコピーして分離する方法、として実験してみようと考えました。OpenMP、OpenMPI、OpenCLなどのライブラリも少し調べたのですが、並列化の方法のニュアンスが違うようなので、可能なところまで自作してみようと思っています。

      補足日時:2015/02/13 11:06
  • ご丁寧に回答をいただいたところ申し訳ないのですが、コールやジャンプの依存がある以上、アセンブリ言語の学習のコストは考慮しています。その上で、関数のメモリ上でのサイズを知る方法にはどのようなものがありますか?
    この部分だけは調べてもなかなか手がかりがないのです。アセンブリ言語を学べばやり方も自ずとわかりますか?それとも言語処理系やコンパイラ方面の知識を要求されるのでしょうか?情報を得るためにどのようなキーワードが適しているか、などの小さなことでもいいのでご回答いただけないでしょうか?

      補足日時:2015/02/14 22:13
  • 自己解決しました。

    よく考えたらシンボルテーブルの残っている実行ファイルをobjdump -dして別のファイルに保存すれば関数名から場所を特定できますし、不要な部分を削って16進表記の関数を手に入れることができ、サイズもわかります。
    メモリの再配置を伴うような複雑な関数は動作しなくなりますが、それを避けるように最適化したコードなら動作するはずです。使用可能な機能、状況は限定的だと思いますが。

    私の基礎知識が不足しているせいで何に使えるかもわかりませんが、一応、最初の質問に対する答えにはなっているので書いておきます。たくさんのヒントを与えてくださった回答者の皆様には重ねて感謝いたします。ありがとうございました。

      補足日時:2015/02/16 00:19

A 回答 (5件)

質問者さんの今の状況は、四則演算も理解していないのに「数学に興味を持ったので、テンソル解析の問題を解いてみたいと思っています。

xxすれば解けるのではないかと思っていますが、Σという記号の意味が分かりません。なんでもよいからヒントを教えてください」と言っているようなものです。

回答している皆さんはどれだけ的外れな質問をされているかは理解した上でご回答されていると思いますが、まず質問者さんご自身が基礎知識を身につけなければハナシになりません。まずフツーにプログラム言語を「利用」できるレベルになって、それから簡単なインタプリタが実装できる程度の知識は身につけましょう。並列計算の「実験」はその後のハナシです。
    • good
    • 0
この回答へのお礼

ご指摘ありがとうございます。

Wr5さん、Tacosanさんに大変なご迷惑をおかけしました。身の程知らずにも不躾な物言いをしたことをお詫びいたします。

基礎知識を学び直した上で出直します。皆様、貴重な時間を割いてお付き合いくださりありがとうございました。

お礼日時:2015/02/15 14:34

>並列計算に興味を持ち、複数のスレッドが干渉し合わないようにスレッドの数だけ関数をコピーして分離する方法、として実験してみようと考えました。



グローバル変数なり使っていなければ普通は他のスレッドへの悪影響とかは出ませんよ?
ローカル変数なら一般的にスタック上に作成されますし、スレッド毎に別々のスタックが用意されるはずです。

むしろ…CPUの1次/2次キャッシュの恩恵が受けられなくなる分、性能が低下しそうではありますが……。
# 最近のCPUなら3次キャッシュくらいまでありますかね。

>並列化の方法のニュアンスが違うようなので、可能なところまで自作してみようと思っています。

そういうレベルでの車輪の再発明はしないですね。私なら…。
演算効率とか極限まで求めるのであれば、ソレ系統な大学や研究室でやるべきかと思いますし。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

>スレッド毎に別々のスタックが用意されるはずです。

そうだったのですか!ローカル変数についての知識が曖昧でした。勉強になります。

可能かどうかの実験をしてみたいだけで、極めてライブラリを作ろうとまでは考えていません・・・性能の低下も現行は意識していません。

最初の「関数のメモリ上でのサイズを知る方法」という質問から次第に遠ざかっている気がするので、新しい質問の補足をお読みいただいた上で、回答に補足をいただけるようであればよろしくお願いします。

お礼日時:2015/02/14 22:50

多分「C言語でやろうとするとやはりアセンブリ言語やアーキテクチャに関する知識は不可欠になってしまいますかね・・・」は誤解だと思います. おそらく


「C言語でやろうとなにでやろうとやはりアセンブリ言語やアーキテクチャに関する知識は不可欠になってしまいますかね・・・」
の方が適切ではないかと. もしそうじゃなくって「他の言語でやれば簡単」ということなら, その「他の言語」を使うことを最初に考えるでしょうし.

ところで「複数のスレッドが干渉し合わないように」ってのがわからないんですけど, 具体的にはどのような状態が「干渉している」ということになるんでしょうか?

以下, ちょっと手元の gcc 4.8.2 (windows) で遊んでみました.

#include <stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
をコンパイルしてできるアセンブリソースを見ると "hello world\n" を RIP 相対アドレスで扱ってますから, 「単純に関数をコピーする」だけでは動かなくなっちゃいます (printf を puts に最適化していたがここでは無視).

と, こんな簡単なプログラムですら一筋縄ではいかないことがわかります. libelf... も直接関係ないだろうなぁ....
    • good
    • 0
この回答へのお礼

丁寧なご回答ありがとうございます。

「複数のスレッドが干渉しないように」とは、「複数のスレッドが同じメモリ領域を参照しないように」という意味です。Wr5さんから指摘をいただいた中に、
>ローカル変数なら一般的にスタック上に作成されますし、スレッド毎に別々のスタックが用意されるはずです。
とありましたので、私の杞憂だったようです。グローバル変数をセマフォで制御することは知っていたのですが、ローカル変数についての私の知識不足でした。

実験までしていただいてありがたいのですが、最初の質問から方向性がずれてきている気がするので、新しい補足をお読みいただいた上でなにかご存知のことがありましたら補足をよろしくお願いします。

お礼日時:2015/02/14 22:33

まずもって, なぜ「鋳型となる関数を用意して、それを別のメモリ上にコピーして実行させる」ことを思いついたのかが謎だったりするわけだが....



この質問文だけでは条件が不足していて, 最低限プロセッサも指定する必要があります. 例えば x86 ならセグメントセレクタ (やそこからつながるページテーブル) も気を付ける必要がありますし, あるいは SPARC だとある種のデータを読み込むときに PC 相対アドレスを使う例がある (だから「関数」だけコピーしても動かないかもしれない) ことも意識しないとダメですからね.

ちょっと #1 に補足しておくと, 今どきのプロセッサを対象とするならほとんどの場合関数内の分岐には相対分岐を使う (だからアドレス修正は不要な) 可能性が高いとは思います. ただし, コンパイラが変わったときにどうなるかは, 当然ですが誰にも保証できません.

余談だけど本来 NX ビットは AMD の表現で Intel では XD ですな.
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

確かに質問の条件が不足していました。補足に書きましたような事情で、なるべくアセンブリ言語に深入りしすぎない方法でと思ったのですが、C言語でやろうとするとやはりアセンブリ言語やアーキテクチャに関する知識は不可欠になってしまいますかね・・・

お礼日時:2015/02/13 11:19

>鋳型となる関数を用意して、それを別のメモリ上にコピーして実行させることを考えています。



今時の環境だと難しいんじゃないですかねぇ……。
OSの挙動に関する知識と、アセンブラの知識が必要そうですが。

ストレージからメモリにロードされた時点で、仮想メモリアドレスに割り当てられますから
関数内の条件分岐などの飛び先アドレスもその際に再割り当てになっているかと。
# 短距離なら相対アドレスジャンプかも知れませんが。
メモリコピーだとこの辺りのアドレスの振り直しが実施されませんよね???
あとは……仮想メモリでの属性として「実行可能」などの属性が設定されていたりするかと思われますが…。
# NXビット…でしたっけ?
    • good
    • 0
この回答へのお礼

迅速なご回答ありがとうございます!

やはり難しいですか・・・

なるほど、条件分岐にもアドレスの再割り当てが行われるのですか。関数アドレスさえ調整すれば大丈夫かと思っていました。メモリの属性はmprotectで変更できるのでコピーすること自体が一番の問題かと思ったのですが、アドレスの再割り当てもかなり厄介そうですね・・・盲点でした(>_<) ご指摘ありがとうございます。

お礼日時:2015/02/12 17:44

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!