FromNandの日記

自分的備忘録

【C言語】constについて気をつけることとか

const指定子がめんどくさいのでまとめておく 

参考 : const修飾子について - Qiita

 

例えば次のコード

const int *i;

i is pointer to read-only int.

int const *i;

i is pointer to read-only int.

int * const i;

i is read-only pointer to int.

上の二つはポインタが指す先を書き換えることができないが、

三つめはポインタ自体を書き換えることができない。

 

一瞬配列自体にconstを付けられるかなんて考えてしまったが、配列はそもそもラベルでしかなく、保存領域を持っていないのでconstなんて適用することはできない。

もちろん、配列の内容に対してはconstを適用することはできるが...

 

またconstのポインタのポインタなんかをとったりするときには、一番端のポインタ変数だけをconstで保護してもそれに至るまでのポインタを書き換えられたりしたら意味がないことが多いのですべてconst修飾するといい。

const int *const *const *const p;

 

constな領域を指すポインタはただのポインタに代入することはできない。

これは当然で、constな領域を代入後のポインタで書き換えることができるようになってしまうから。

 

これと同様の原理で、もしconstになるべきライブラリの引数にconstがついていなかった場合、それを呼び出す実引数はconstを取りやめざるを得なくなる。

また、constつきの引数を取る関数の中でさらにその引数を他の関数に渡したりすることがあると思うが、この場合、中で呼び出す関数もconst付きのプロトタイプ宣言をしておかねばならない。

 

 

ローカル変数につけたconstは文法上で書き込みは不可能になるが、ポインタをキャストしたりして無理やり書き込んだ場合は実際には書き込めてしまう。

これはローカル変数がスタックに置かれるためだ。

一方でグローバル変数につけたconstは書き込み不可領域に置かれることが多いようだ。

 

 

これぐらいかなぁ、追記するかも。

【アセンブラ】アセンブラによってORG疑似命令の意味が違う!?

これまでにそれなりの種類のアセンブリを見てきたけど、混乱した箇所があったため整理する。

それは、ORG疑似命令についてである。

実はこの命令、アセンブリの種類によって意味が全く違うのである。

 

例えば、GASではORGは次のような意味になるらしい。

.org [size] [, fill]

そのファイルの先頭から[size]分だけ[fill]で埋める。

[fill]が指定されなかった場合、デフォルトは0である。

例) .org 0x7c00

 当然これをアセンブルすると、0x7bffまでぎっしり0で埋まったバイナリファイルが完成する。

 

次は、NASM・MASMの場合

ORG 0x7c00

JMP 0x100

これをアセンブルすると、おそらく3byteくらいのバイナリファイルが完成する。

ここでのORGの意味はVMAを指定するという意味である。

よってJMP命令は0x7c00を基準として行われる。

この3byteは「opecode 00 7d」みたいな機械語に変換される。

 

【GASではどうすればいいか?】

今回はgas,nasm,masmを比較したが、GASでほかの2つのアセンブリ言語のORGと同じことをしたいとしたらどうすればよいだろうか。

これに関しての自分の考えはldの際にリンカスクリプトとしてVMAを指定してリンクするしかないように感じる。

 

参考

assembly - gas .org different from ORG in nasm? - Stack Overflow

【SUFFIXES】makeにおけるサフィックスルールとは?

サフィックスルールとは、ある拡張子が現れたときに適応されるルールのこと。

例えば「.c」であれば、もともとあるサフィックスルールに則って「.o」ファイルが生成されたりする。

参考 : http://exlight.net/devel/make/basics.html

 

この行でデフォルトのルールを無視するように設定

この行を書かずに下の①だけかくと、以前のサフィックスルールに規則を付け足す形になってしまうので、自分で全部決めたい場合は絶対に書くこと。

.SUFFIXES :

 

この行で独自のサフィックスを設定(①)

.SUFFIXES : .o .c .s

 

.cファイルから.oファイルを作る

$<はコンポーネントのファイル名(suffixを含む)

.c.o : $<

    $(CC) $(CFLAGS) -c $<

.s.o : $<

    $(AS) $(ASFLAGS) -c $<

 

makeについて色々まとめてみた

makeについてまとめておく。(参考書籍 oreilly make 改訂版)

 

1. makeはファイルの依存関係をOSに記録された各ファイルの情報をもとに詳細に理解

 し、各ファイルを構成しているコンポーネントが最新であればコマンドを無視、そう

 でなければmakefileにかかれた依存関係をもとにコマンドを実行し、ターゲットを

 更新するという再帰的な処理を行っている。

 

2. マクロ定義部では=の前後の空白やタブはすべてないものとして処理される。

 また、行を続けるために書かれた'\'は前後の空白やタブとまとめて一つの空白として

 処理される。

 

3. makeではよくつかわれるコマンドをあらかじめマクロとして定義してある。

 $(CC)はcc、$(LD)はldなど....

 

4. コマンドラインからmakeを実行するときにマクロを定義することもできる。

 例) make target DIR=/bin

 この場合、targetとマクロの定義の順番は問わない。

 例2) make target "DIR= /bin /usr /usr/prog"

 マクロの定義が複数の文字列を含み、タブや空白を持つ場合は ' か " で囲む必要が

 ある。

 

5. makeではマクロを定義するが、例えば環境変数コマンドライン上で定義した

 マクロ、内部マクロなどの優先順位はどうなのだろうか。

 大まかに分けると次のようになるらしい。(1が優先順位が高い)

 

 1. コマンドライン上でmakeよりも後に定義されたマクロ。(4参照)

 2. makefile内で定義されたマクロ。

 3. 環境変数

 4. makeであらかじめ内部定義されているマクロ。

 

 ただ、環境変数makefile内の定義よりも優先した以上ができたとする。

 その時は-eオプションを付けると上記の2番と3番の優先順位が入れ替わる。

 

6. マクロの中の一部の文字列だけを置換したくなったとする。

 例えば、~.cを大量に並べていたが、それぞれのオブジェクトファイル~.oも

 マクロとして使用したくなった時などだ。

 この時は、マクロを参照するかっこのなかに少し技巧を凝らす。

 SRC=src1.c src2.c というマクロがあったとすると、$(SRC:.c=.o)と参照することで

 src1.o src2.oと置き換わる。

 もし.c丸ごとなくしたいならば=の後には何も書かなければいい。

 ただし、このような置換は文字列の最後の直前もしくは、空白の直前のみ行われる。

 

7. 便利な自動定義マクロ。

 $@は現在処理中のターゲット、つまり : の左のファイルを表す。

 $?はコンポーネントリスト、つまり : の右側のファイルのリストのうち、

 ターゲットよりも新しいものをすべて表す。

 しかし、$?については注意が必要である。gccという有名なコンパイラドライバに

 オブジェクトファイルを指定するとき、$?を用いると痛い目にあうことがある。

 gccはリンクするファイルをすべて同時に指定しなければならないからである。

 また、これらはコマンド行でのみ有効なマクロである。

 $$@というものもある。先ほどの$@との違いは依存関係行、つまり : の行でのみ

 使えるということである。

 target : src1.c $$@.c とすると$$@はtargetであるから$$@はtarget.cとなる。

 

8. サフィックスルールというものがある。有名なものを挙げておく。

 src.oがコンポーネントとして必要なターゲットがあったとする。

 しかし、src.oは存在しなかった。

 このとき、makeは次のようにしてsrc.oを作り出そうとする。

 まず、src.oに関する依存関係の行がないか探す。なかったら次のようにする。

 1-src+サフィックスのファイル名をもつファイルがある。

 2-makeにとって意味のあるサフィックスを持っている。(.c .s .fなど)

 3-定義されているサフィックスルールでsrc.oを作ることができる。

 この三つを満たすファイルをカレントディレクトリから見つけだし、

 あらかじめ定義されたサフィックスルールにのっとって処理する。

 また、サフィックスルールの中では$?の代わりに$<を使う(重要!)

 $*というマクロもある。これもサフィックスルールでのみ有効であり、

 コンポーネントのファイル名のサフィックスを除いた文字列に置き換わる。

 実際のサフィックスルールの書き方については別ページにまとめておく。

【GCC】OS開発(組み込み)でよく使用するオプション

https://qiita.com/h_hiro_/items/4db6a7478fb0ff333d9f」が参考になります。

 

【AS・GCC(狭義のコンパイラ)・LDで32bitのバイナリを生成するオプション】

 

as --32

gcc -m32

ld -m elf_i386

 

GCC(コンパイラドライバ)におけるオプション】

 

-Wall

警告をすべて表示する。

 

-nostdinc

ヘッダファイルの検索において、システム標準のディレクトリを対象としない。-Iオプションで指定したディレクトリ(と、状況によるがカレントディレクトリ)のみが検索対象となる。

 

-nostdlib

リンク時にシステムスタートアップのファイルやライブラリを利用しない。明示的に指定したライブラリのみがリンカに渡される。またシステムライブラリを使うためのオプション(-static-libgcc-shared-libgcc)も無視される。

 

-fno-builtin

コンパイラのビルトイン関数を利用しない。

gccでは改行を最後にもつprintfをputsに置き換えたりするが、このようなことを抑制する。

細かいことは「http://blog.kmckk.com/archives/926992.html

 

-fno-pic

位置独立コードの生成。

似たようなオプションや詳細は「https://fromnand.hatenadiary.jp/entry/2019/09/16/000053

 

-mint32

intを32bitとする。

 

-I(アイ)

ヘッダファイルの検索先を指定する。

上のnostdincと組み合わせることが多い。

 

-g

デバッガを利用する場合に指定するとよい。

 

-O(0, 1, 2, s)

-O0は最適化レベル0。

-O1は最適化レベル1。

-O2は最適化レベル2。

-Osはサイズの最適化を行う。

 

-static

ライブラリを静的リンクする。

 

-T

リンカスクリプトを指定する。

-Tを使わずにリンカスクリプトコマンドラインに打ち込んでも勝手に認識するらしいけど...

 

-L

ライブラリの検索先を指定する。

あんまり使わない...??

 

gccコンパイラドライバを意味しているときは、「as」「ld」のオプションも指定できる(当然)。