OSSライセンスの種類と使うべきライセンス
ライセンスの種類
OSSライセンスは以下の3つに分類されます。
それぞれ以下のような違いがあります。
分類 | 改変部分の公開義務 | 改変部分以外の公開義務 |
---|---|---|
コピーレフト型 | 有り | 有り |
準コピーレフト型 | 有り | 無し |
非コピーレフト型 | 無し | 無し |
コピーレフト型の場合は、プログラム全体を公開する義務が発生します。例えば、プログラムに少しでもコピーレフト型でライセンスされたプログラムが含まれていると、プログラム全体を公開しなければなりません。
準コピーレフト型の場合は、改変部分にのみ公開義務が発生します。
非コピーレフト型の場合は、改変後の公開義務はありません。
どれを選択すべきか
特段理由がない限り、非コピーレフト型のライセンス(MIT, BSD, Apacheなど)を利用することが望ましいです。前項を見ていただくと分かりますが、コピーレフト型には開示義務が発生するため商用利用が厳しいという欠点があります。非コピーレフト型であれば、著作権などの必要事項を表記するだけで自由に使うことができます。コピーレフト型のライセンスは、シェアによる改善を前提とするときに使用すると良いでしょう。
UbuntuのPPAをRaspbianに追加する方法
はじめに
Raspbianに入っているツール、デフォルトだと結構バージョンの低いものが多いです。「新しいバージョンが使いたい!」というときに、RaspbianにもPPAを追加できたら便利ですよね。今回はRaspbianにPPAを追加する方法を紹介します。
手順
今回は例としてppa:ubuntu-toolchain-r/testを追加してみます。
1. PPAのキーを登録
$ sudo apt install dirmngr $ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 60C317803A41BA51845E371A1E9377A2BA9EF27F
キーは使用したいPPAのキーに適宜変更してください。キーはPPAサイトのFingerprint
の欄に記載されているものを使用します。
2. リポジトリのURLを設定
deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu bionic main deb-src http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu bionic main
/etc/apt/sources.list.d/
にubuntu-toolchain-r.list
というファイルを作成し、上記の内容を記述します。記事執筆時点で使用可能な最新のLTSがUbuntu 18.04(Bionic Beaver)だったため、bionicを指定しています。
3. パッケージの更新
sudo apt update
これで作業は終了です。あとは必要に応じてupgradeするなりinstallするなりしましょう。
GDBでコアダンプ解析
今回はコアダンプを用いたGDBでのデバッグ方法を解説します。
そもそもコアダンプとは
Wikipediaでは以下のように説明されています。
コアダンプは、ある時点の使用中のメモリの内容をそのまま記録したものであり、一般に異常終了したプログラムのデバッグに使われる。
記載されてある通り、プログラムが異常終了した際の原因解明に役立ちます。実際どのように使うのか見ていきましょう。
コアダンプの有効化
デフォルトでは大抵コアダンプ機能が無効であるため、以下のコマンドで有効化しておきます。
$ ulimit -c unlimited
(起動時に有効化する場合は~/.bashrc
にでも書いておきましょう。)
テストコード
コアダンプが発生する原因には様々なものがありますが、そのうちの1つにセグメンテーション違反(不正なメモリアクセスによる違反)があります。以下のコードを実行すると、Nullポインタアクセスによるセグメンテーション違反が発生します。
#include <iostream> int entity(int *p) { return *p; } int main() { int *p = nullptr; std::cout << entity(p) << std::endl; return 0; }
原因は分かる人には一目瞭然ですが、今回は例としてこのコードをデバッグしてみます。後にデバッグ情報が使用できるように、-g
オプションをつけてビルドしてみましょう。
$ g++ -g main.cpp $ ./a.out Segmentation fault (core dumped)
セグメンテーション違反が起き、coreファイルが生成されます。
デバッグ
いよいよデバッグです。coreファイル付きでGDBを起動してみましょう。
$ gdb ./a.out core ~(中略)~ Core was generated by `./a.out'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0x00005605081471b9 in entity (p=0x0) at main.cpp:4 4 return *p;
引数にNullポインタが渡されており、4行目の参照外しが原因となっていることが分かりますね。
バックトレースも見てみましょう。
>>> bt #0 0x00005605081471b9 in entity (p=0x0) at main.cpp:4 #1 0x00005605081471dd in main () at main.cpp:9
9行目でentity関数を呼び出したのが原因であることが分かります。こうやって異常終了の原因を探るわけです。
最後に
単純なコードならまだしも、複雑なコードだとバグの原因がすぐに分からないことって意外とあります。そんな時はぜひコアダンプを活用してみてください。
おっと、デバッグ関連で思い出しましたが、最後に筆者オススメのGDB dashboardのリンクを貼っておきます。なぜオススメかは、、、またの機会ということで。
AArch64でHello, World!
AArch64とは
Armアーキテクチャの64bit拡張。ARMv8-Aアーキテクチャより導入されている。
環境構築
いつも通り、GCCとQEMUのユーザーモードエミュレーションを使用する。
$ sudo apt install gcc-aarch64-linux-gnu qemu-user
コード
コメントアウトする時は//
を使用する。
.text .global main main: str x30, [sp, #-8]! ldr x0, =msg bl printf mov x0, #0 // return 0 ldr x30, [sp], #8 ret .data msg: .asciz "Hello, World!\n"
実行
$ aarch64-linux-gnu-gcc hello.s $ qemu-aarch64 -L /usr/aarch64-linux-gnu/ a.out Hello, World!
解説
str x30, [sp, #-8]!
x30をスタックに積んでいる。x30はリンクレジスタの役割を果たすため、Armでいうところのpush {lr}
である。
ldr x0, =msg
x0にmsgラベルのアドレスをロードしている。これはprintfの第一引数として使用される。
bl printf
printfを呼び出す。
mov x0, #0
C言語でいうreturn 0
。正常終了であることを意味する。
ldr x30, [sp], #8
スタックに積んでいたリンクレジスタの値を元に戻す。Armでいうpop {lr}
。
ret
関数終了。オペランドに何も指定しない場合は、ret x30
と同じ意味になる。
RustでArmバイナリをビルドする
はじめに
今回はRustでArmバイナリをビルドする手順について紹介します。記事を作成するにあたり、以下の記事を参考にさせていただきました。
実行環境
- Ubuntu 20.04 LTS (WSL2)
1. 新しいプロジェクトの作成
今回は例としてhelloという名前でプロジェクトを作成します。
$ cargo new hello $ cd hello $ cargo run
Hello, world!
と表示されればひとまずOK。
2. .cargo/config
に設定を記述
.cargo/config
にクロスコンパイルするための設定を記述します。今回はtargetにarm-unknown-linux-gnueabi
を、linkerにarm-linux-gnueabi-gcc
を指定します。
.cargo
ディレクトリの作成
$ mkdir .cargo
.cargo/config
の中身
[target.arm-unknown-linux-gnueabi] linker = "arm-linux-gnueabi-gcc"
3. ツールチェーンを追加し、リンカをインストール
$ rustup target add arm-unknown-linux-gnueabi $ sudo apt install gcc-arm-linux-gnueabi
4. ターゲットを指定してビルド
$ cargo build --target=arm-unknown-linux-gnueabi
5. QEMUで実行
$ qemu-arm -L /usr/arm-linux-gnueabi/ target/arm-unknown-linux-gnueabi/debug/hello
Hello, world!
と表示されれば成功です。
RISC-VでHello, World
RISC-Vとは
以下、Wikipediaより引用(Wikipediaのライセンスに基づく)。
RISC-V(リスク ファイブ)は、確立された縮小命令セットコンピュータ (RISC) の原則に基づいたオープン標準の命令セットアーキテクチャ (ISA) である。他の多くのISA設計とは異なり、RISC-V ISAは、使用料のかからないオープンソースライセンスで提供されている。多くの企業がRISC-Vハードウェアを提供したり、発表したりしており、RISC-Vをサポートするオープンソースのオペレーティングシステムが利用可能であり、いくつかの一般的なソフトウェアツールチェーンで命令セットがサポートされている。
事前準備
以下の記事を参考に。今回はLinux cross-compiler RV64GC
とqemu-riscv64
を使用する。
使用する命令
通常命令
命令 | 意味 |
---|---|
addi | 加算 |
ld | メモリから値をロード |
li | 即値をロード |
sd | メモリに値をストア |
疑似命令
命令 | 同義 | 意味 |
---|---|---|
call | jalr ra, ra, offset | 関数呼び出し |
la | lui rd, %hi(offset); addi rd, rd, %lo(offset) |
アドレス(ラベル)をロード |
ret | jalr zero, ra, 0 | サブルーチン終了 |
使用するレジスタ
レジスタ | 役割 |
---|---|
a0 | 第一引数及び戻り値 |
ra | リターンアドレス |
sp | スタックポインタ |
※スタックポインタを動かす場合は、16の倍数に整列するようにする。
Hello, World
.text .globl main main: addi sp, sp, -16 la a0, msg sd ra, 8(sp) call printf ld ra, 8(sp) li a0, 0 # return 0 addi sp, sp, 16 ret .data msg: .asciz "Hello, World!\n"
実行。
$ riscv64-unknown-linux-gnu-gcc hello.s $ qemu-riscv64 -L /opt/riscv/sysroot/ a.out Hello, World!
参考
浮動小数点数の扱い方(Arm)
はじめに
Armには、浮動小数点数を扱うためのVFPと呼ばれる機構が用意されている。今回はこれを用いて、浮動小数点数の表示をしてみよう。
C言語
今回例として作成する処理は、C言語で書くと以下のようになる。円周率3.14
を表示するというものだ。
#include <stdio.h> int main(void) { printf("%.2f\n", 3.14); return 0; }
アセンブリ
アセンブリで書くと以下のように書ける。
.fpu vfp .text .global main main: push {lr} ldr r0, =value vldr d0, [r0] ldr r0, =msg vmov r3, r2, d0 bl printf mov r0, #0 @ return 0 pop {pc} .data msg: .asciz "%.2f\n" value: .double 3.14
実行。
$ arm-linux-gnueabi-gcc pai.s $ ./a.out 3.14
解説
今回は初めて登場したvldr
とvmov
について解説。
vldr
vldrは、指定したメモリから拡張レジスタに値をロードするという役割を持つ。上記の例では、直前にvalue(3.14がある場所)をr0に読み込んでいる。つまり、vldr d0, [r0]
はvalueの実体(3.14)をd0に読み込んでいる。
vmov
vmovは代入命令である。vmov Rd, Rn, Dm
の形式の場合、上位bitはRnに、下位bitはRdに代入される。printfの第二引数にdouble型を指定する場合はr2とr3が使用されるため、vmov r3, r2, d0
となる。