• ベストアンサー

アドレスを指定して関数を呼び出す方法は有りますか

 マイコンのROMに書いてある関数を呼び出すのに、次のような方法を使っています。  1000番地のsub1と言う関数を呼ぶのにアセンブラで次のように書き、リンカで結合しています。 sub1: EQU 1000  これをアセンブラを介せずC言語だけで行う方法は無いでしょうか。 イメージ的には次のような感じで1000番地のプログラムを呼びたいのです。  この方法では上手く行かないのは分かっていますが、それを何とかしたいと思っています。 #define sub1 1000 sub1() ;  宜しくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8536/19407)
回答No.7

定数を関数へのポインタにキャストすれば良い。 #define sub1 1000 main() { int i; int i; i = ((int (*)(int,int))sub1)(10,20); /*intの引数が2つあってintを返す関数*/ }

richardo
質問者

お礼

 やった! 有難う御座います。  コンパイルすると、下記の結果になりました。 ------------------------------------------- #define sub1 0x1000 int i ; ((void (*)(void ))sub1)( ); i = ((int (*)(int,int))sub1)(0x10,0x20); ------------------------------------------- JSR @H'01000:24 MOV.W #H'0020:16,E0 MOV.W #H'0010:16,R0 JSR @H'01000:24 ------------------------------------------  更に次のようにすると、普通の関数と変わり無く使えるのが分かりました。 ---------------------------------------------- #define sub2 ((void (*)(void ))0x2000) sub2() ; #define sub3 ((int (*)(int,int))0x3000) i = sub3(0x30, 0x40) ; --------------------------------------------- JSR @H'02000:24 MOV.W #H'0040:16,E0 MOV.W #H'0030:16,R0 JSR @H'03000:24 ---------------------------------------------  このような複雑な書き方はI/Oポートの構造体とか、C言語のクイズのような物で見るだけで、解説本には見かけないと思います。  どうも有難う御座いました!

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (7)

  • chie65535
  • ベストアンサー率43% (8536/19407)
回答No.8

蛇足ですが。 >更に次のようにすると、普通の関数と変わり無く使えるのが分かりました。 >#define sub2 ((void (*)(void ))0x2000) >#define sub3 ((int (*)(int,int))0x3000) ROMの内容は不変だと思いますので、ROMの関数のアドレスも不変だと思います。 なので、これらのROM関数の定義を以下のようにヘッダーファイル rom.h に書いて、いつもそれを使うと良いでしょう。 ---rom.h--- #define InitSerialPort ((void (*)(void))0x1200) #define ResetSerialPort ((void (*)(void))0x1258) #define ReadSerialPort ((char (*)(void))0x12A2) #define WriteSerialPort ((void (*)(char))0x12E4) (以下略) ※関数名とアドレスは架空の物です。実在の関数名とアドレスとは一切関係ありません。 名前も、sub1とかsub2ではなく、上記のように「意味がある名前」にしましょう。 そうすれば、実際に使う場合、以下のように書くだけで良く、毎回#defineを書かずに済みます。 #include <rom.h> void main(void) {   int r;   char readbuf[10];   InitSerialPort();   ResetSerialPort();   WriteSerialPort('R');   WriteSerialPort('0');   WriteSerialPort('1');   WriteSerialPort('S');   readbuf[0] = ReadSerialPort();   readbuf[1] = ReadSerialPort();   readbuf[2] = ReadSerialPort(); (以下略)

richardo
質問者

お礼

 分かりました。  色々と有難う御座いました。  また何か有りましたら宜しくお願いします。

全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.6

>別にアセンブリしたりサブ・コマンドファイルの変更などが有り。 ここら辺は工程をバッチファイル化したり、ROM側のリンク時にシンボルファイルを書き出してJavascript/VBScriptなどで加工してアセンブラソースに加工するってのが定番です。 C言語だけでやると問題としては、 1.関数にパラメータがあるとキャストがめんどくさい。 2.リンカだけで解決するよりコードがわずかだが肥大化する。 3.関数ポインタの初期化を忘れてもエラーが出ない。リンクならエラーが出るからすぐ分かる。

richardo
質問者

お礼

 再度回答ありがとう御座います。  今までの方法が、最良だったという事ですね。

全文を見る
すると、全ての回答が全文表示されます。
  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.5

>#1さん 確かに関数ポインタを使えばよいですが、だからといって >void(*sub1)(void) = 1000; これはないでしょう。 # 本当に専門家?

richardo
質問者

お礼

 回答有難う御座います。  名前はパラグアイの首都アスンシオンですか?  20年前にアスンシオンの友人の家に数ヶ月滞在していたので、懐かしいなと思って。

全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.4

私もjactaさんと同じでリンカでの解決が良いと思います。 アセンブラによるのですが、 _sub1:: EQU 1000 とか外部シンボルになる定義を行ってください。 ※ この場合::が外部シンボルの意味となる。そのほかexternと書くものや色々アセンブラによって違います。アンダーバーが必要かもC言語コンパイラの仕様によって変わります。 C言語側では、 extern void sub1(void); と宣言して、 sub1(); と呼び出すだけです。

richardo
質問者

お礼

 早速の回答ありがとう御座います。  秋月電商のH8キットでプログラムを作っているのですが、printf 関数は大きくてRAMに入りません。  それでROMに書き込んで呼び出しています。  現在zwiさんの回答と同じ方法でリンカで解決しているのですが、C言語の機能を引き出してC言語で解決できる道を探しています。

全文を見る
すると、全ての回答が全文表示されます。
  • notnot
  • ベストアンサー率47% (4853/10268)
回答No.3

C言語の枠を外れる話ですが、組み込み系のCコンパイラなら、そのコンパイラでどう記述するか機能が提供されていると思うので、コンパイラのマニュアルを見ましょう。 見つからなければ、だめもとで#1の方の書いた方法。

richardo
質問者

お礼

 早速の回答ありがとう御座います。  秋月電商のH8キットの安いコンパイラを使っています。  コンパイル時間が短いので気に入っています。  シンプルな所が気に入っています。  シンプルだから、基本的な事しか出来ません

全文を見る
すると、全ての回答が全文表示されます。
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

一番確実なのは、アセンブリ言語のソースで、関数名が外部結合のシンボルになるような擬似命令を記述することです。 関数へのポインタを使えばほとんどの場合動作しますが、規格上保証されているわけではありませんので。

richardo
質問者

お礼

 早速の回答有難う御座います。  現在はアセンブリ言語の EQU を使って結合しているのですが、C言語だけで行う方法を探っています。  アセンブリ言語が絡んでくると、別にアセンブリしたりサブ・コマンドファイルの変更などが有り、ミスが増えそうなのでC言語だけで処理出来ないかなと思っています。

全文を見る
すると、全ての回答が全文表示されます。
  • hegemon
  • ベストアンサー率72% (21/29)
回答No.1

関数ポインタを使えば可能です。 void(*sub1)(void) = 1000; sub1();

richardo
質問者

お礼

 早速の回答有難う御座います。  このような回答を待っていました。  しかし次のプログラムを書いてコンパイルしたのですが、 2129(E) ILLEGAL INITIALIZER TYPE と言う、エラーメッセージが出てしまいます。 void test(void) { void(*sub1)(void) = 1000; sub1(); }  次のようにしても同じでした。 void(*sub1)(void) = 1000; void test(void) { sub1(); }  関数ポインタという機能を調べて、自分でも実験してみます。

richardo
質問者

補足

 下記のお礼の補足です。  使っているコンパイラが秋月電商のH8マイコン用です。  機能が小さくて、C言語機能全体をカバーしていないかも知れません。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • H8Sで割り込み発生時の飛び先アドレスがRAM上にある場合の割り込み関数の記述方法

    ルネサスのマイコンH8Sのプログラムを組んでおります。 プログラムの構成がBoot部分とアプリケーション部分に分かれており、 Bootはアドレス0番地から、アプリは3000番地以降の領域を使用するようになっています。 完成されたBootを使用してアプリケーションのプログラムを組まなければならなく、また、Bootは変更できないことになっています。 このBootの中のベクターテーブル上で、割り込みが発生した場合の飛び先のアドレスがRAM上になるように設定してあります。 このため、アプリケーションソフトでは、 割り込みが発生した場合のRAM上の飛び先に FLASH ROM上の指定したアドレスにジャンプする命令を書き、 FLASH ROMのジャンプ先には、実行したい関数を書きたいのですが、 (1)RAM上の特定のアドレスからFLASH ROM上の指定したアドレスにジャンプさせる方法。 (2)FLAH ROM上の指定したアドレスに関数を記述する方法。 を知りたいのですが、 どなたか教えて頂けないでしょうか? 開発環境はHew4 言語はC言語を使用しております。 私自身が理解不足であるため質問内容が伝わりにくいかと思いますが、 宜しくお願い致します。

  • PIC C言語でコード開始アドレスを指定する方法

    PIC18F2550用にMPLAB-IDEでC18コンパイラを使って、作ったファイルをUSB経由でブートしようとしています。下位番地にはブートローダが入っているため、プログラムの開始アドレスを800番地以降におきたいのですが、例えばアセンブラ言語のORG命令のようにコードの開始番地を指定することはできないでしょうか?

  • 割り込みベクターをC言語で書きたい

     皆さん、有難う御座います。時々質問させて頂いています。  今回は、ベクターアドレスをC言語で書く方法について質問します。  ルネサスのH8マイコンを使っています。モニターを使うとRAM上に割り込みの仮想ベクターを作れます。  仮想ベクターには、割り込みのジャンプ先アドレスが書かれます。  現在アセンブラで書いているのですが、C言語で書く方法は無いでしょうか。  二つの方法で書きたいと思っています。  アセンブラで次の二つの方法に相当するC言語命令を知りたい。 (1)ORGとEQU命令を使った方法 (2)ムーブ(Z80ならロード)命令で関数のアドレスをメモリに書く方法  ルネサスにはHEWと言うソフトが有りますが、HEW特有の命令によらず、一般的なコンパイラが持っている機能で実現したい。  以上宜しくお願いします。

  • アセンブラからC言語に変換するにはどうすればいいのでしょうか?

    アセンブラのプログラムをどうにか解読して、C言語に置き換えようとこつこつ行っています。 ですが、プログラム量が多いので解読に時間を要してしまいます。 どうにかして変換したいのですが、手早く変換できる方法はありませんでしょうか? また、自分で調べても分からない単語があります。(見落としているかもしれませんが)  .EQU   .BEQU この二つのコマンドが何を示しているのかがわからないのでこれについても教えてもらえたらうれしいです。

  • メモリ上にプログラムをロードして実行したい!!

    C言語とマイコンで遊んでる者です。 タイトルの通りSDカードやCF等の記録媒体からマイコンのRAM上にプログラムをロードして実行させたいのですが方法がよく解りません。 説明しにくいのですが、PCで言うところのBIOSみたいな物を予めマイコンに書き込んでおいて、そのプログラムが外部のストレージの中に有る実行ファイルのようになってるプログラムデータをメモリ上にコピーして、処理をそのプログラムのエントリーポイントに受け渡すようなOSモドキみたいな物を作りたいのです。 アセンブラならLDとかMOVとかでメモリにコピー出来るかもしれませんが、C言語ではどのようにしてコピーするのでしょう? 仮にメモリ上にコピー出来てもmain()関数が重複してしまい呼び出す方法が解りません。 こちらもアセンブラならばプログラムカウンタをロードした位置にしてやればいいのでしょうけれど。 C言語ではできないでしょうか? マイコンはAVRかSH2Aで考えています。 何方かご教授願います。

  • 1900年代のIAR製アセンブラについて

    日立の古いマイコンH8/325のアセンブラソースで1990年代のIAR製アセンブラを使用したと思われるプログラムをメンテナンスしたいと思います。当時のアセンブラやリンカ、マクロのマニュアルを入手することはできませんでしょうか?ご存じの方がおられましたらご教示下さい。

  • 再帰関数のインライン展開

    再帰関数のインライン展開は出来るのでしょうか? もし、出来るようならアセンブラではどのように表現されているんですか? C以外の言語でも、再帰関数のインライン展開が出来るプログラム言語があれば教えてください。

  • アセンブラからCの関数を呼び出すには?

    「OS自作入門」を読んで試しています。 フロッピーのブートセクタに自作のブートプログラムを 書き込み、ブートプログラムから自作のOSを呼び出して実行 しています。自作といっても前述の参考書の物まねですが・・・・。 ここまでは全てアセンブラでプログラムを書いてきました。 NASMを使っています。ずっとアセンブラではきついので C言語で書きたいのです。 まずは自作のOSからCで書いた関数を呼び出して実行したいの です。つまり・・・ OS.ASM + TEST.C→OS.BIN としたいのです。OS.ASMは自作のOSです。TEST.CにはCの関数を 書いておき、OS.ASMから呼び出すようにします。 これらをくっつけてOS.BINというファイルにしたいのです。 どうすればいいでしょうか?  (1) ブートプログラムの中で16ビットモードから32ビットモードに 切り替えており、自分でセグメントを決めてあります。TEST.Cも それにあわせる必要があるかと思いますが、どうすれば? (2) OS.ASMとTEST.Cをどうやってくっつけるのかがわからない。 リンカーとか使うのでしょうか?

  • 指定アドレスにジャンプさせたい場合【C言語】

    こんにちわ。 この度、初めてOK Waveから質問させて頂きます。どうぞ宜しくお願い致します。 現在、ルネサス製RX62Nを使ったマイコンボードを使用して、C言語によりプログラムを組んで様々な動作をさせているのですが、「RX62N内部のFlashROMの指定したアドレスにジャンプさせる方法」がうまくいかず、どなたか良い方法を教えて頂きたいと思います。 具体的には、変数Aに格納した値(32bit)をアドレスとして扱い、そのアドレスにジャンプしたいと考えています。 以前、他のかたの質問の回答で、  typedef void (*FN_PROGRAM)(void);  FN_PROGRAM pg = (FN_PROGRAM)0x20000000;  (*pg)(); という記述方法で20000000番地にジャンプできると記載があったため、早速、アドレスを0xFFFC0000に変更して動作させてみたところ、0xFFFC0000番地にジャンプさせる事ができ、大いに役に立ちました。 今回、私の方では、始めから0xFFFC0000番地と決め打ちせず、色々と計算をした後、最終的に決まったアドレスを変数Aに格納し、その格納した値をアドレスとして扱い、そこにジャンプさせる方法をとりたいと考えています。 お手数ですが、上記方法で、良い記述方法があればアドバイス頂けないでしょうか。できれば、使う変数Aの宣言文から教えて頂けると有難いと考えています。 説明が下手で申し訳ありません。C言語初心者ですので皆さまから色々とアドバイス頂けると助かります。よろしくお願い致します。、

  • C、C++、Peal、PHPその他「高級言語」といわれる言語について

    僕はPICマイコン(16シリーズ)を趣味で使っており 言語はアセンブラを使っています。 で、質問なんですが最近ホームページを作りたくなり LINUXの勉強も含め自宅サーバーを立ち上げCGIをやってみようと思いました。 で、CGIといえばPealだろと思っていたので、その手の入門書や ネットの情報を見ると冒頭には大抵「大して難しくない」的な事が 書いてありました。 実際にやってみたんですがチンプンカンプンでした。 イメージとしては下記のような感じなんだと思うんですが マイコンのアセンブラと比べたらよっぽど低級言語な気がしてなりません。 アセンブラ=低級言語=人間にわかり難い C、C++等=高級言語=人間に解り易い アセンブラもはじめはチンプンカンプンでしたが、ある程度理解してしまえばそれなりに使いこなせるようになりました。 マイコンのアセンブラは命令数も少ないしイエスかノーだけで「もしも~」とかないので単純といえば単純なんですが・・・ 質問1 高級言語の「人間に判りやすい」っていうのは具体的にどういうことなんでしょうか? 質問2 最近やたらとPHPが流行ってる気がします。 もうPealは廃れてしまったんでしょうか?

    • ベストアンサー
    • Perl