コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2019年8月12日 >>> 2019年7月16日
link もっと後

2019年8月12日

独自のaptサーバー - その3 - aptの信頼システム

目次: apt

Packagesには各Debianパッケージのハッシュ値が記述されていて、悪意ある者がDebianパッケージを改変しても検知できるようになっています。ReleaseにはPackagesのハッシュ値が記述されていて、Packagesを改変されても検知できるようになっています。

Releaseの改変に対しては、サーバーの作成者が署名を付け、Releaseが作成時から改変されていないことを保証します。

パッケージ(*.deb) <--(ハッシュ値)-- Packages <--(ハッシュ値)-- Release <--(署名)-- InReleaseもしくはRelease.gpg

保証の関係を図示すると上記のとおりです。前回のapt-get updateのエラーメッセージはInReleaseもしくはRelease.gpgが存在しない、もしくは、あっても信頼できない署名だと言って怒っているのです。

秘密鍵、公開鍵の作成

最初からapt-getに信頼されている鍵は公式サーバーが使っている鍵ですが、当然ながら私は知りません。ですので、

  • 秘密鍵、公開鍵を作成
  • 自作した鍵をaptに信用してもらう
  • 自作した鍵でReleaseファイルに署名

という手順を取ります。

自分用の秘密鍵、公開鍵を作成
# gpg --gen-key

gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Note: Use "gpg --full-generate-key" for a full featured key generation dialog.

GnuPG needs to construct a user ID to identify your key.

Real name:
...

名前やメールアドレスを聞かれるので適宜答えてください。途中でパスフレーズを聞かれます。今回はテストなので、名前はTest User、パスフレーズはabcd1234にしました。

自作した鍵をaptに信用してもらう

自作した鍵をaptに信用してもらうには、公開鍵(秘密鍵ではありません)をaptの信頼済み鍵束に登録します。

自分用の公開鍵をエクスポートしaptに登録
# gpg --list-keys

/root/.gnupg/pubring.kbx
------------------------
pub   rsa3072 2019-08-11 [SC] [expires: 2021-08-10]
      A24D479395FF7F2B4A787D29439D445DCA4AF8F6      ★このIDを指定する
uid           [ultimate] Test User
sub   rsa3072 2019-08-11 [E] [expires: 2021-08-10]


# mkdir /var/www/linux/debian/gpg
# gpg --export A24D479395FF7F2B4A787D29439D445DCA4AF8F6 > /var/www/linux/debian/gpg/public.key


# curl http://192.168.1.1/linux/debian/gpg/public.key | apt-key add -

# apt-key list

/etc/apt/trusted.gpg
--------------------
pub   rsa3072 2019-08-11 [SC] [expires: 2021-08-10]
      A24D 4793 95FF 7F2B 4A78  7D29 439D 445D CA4A F8F6    ★自作の鍵が追加された
uid           [ unknown] Test User
sub   rsa3072 2019-08-11 [E] [expires: 2021-08-10]

/etc/apt/trusted.gpg.d/debian-archive-buster-automatic.gpg
----------------------------------------------------------
pub   rsa4096 2019-04-14 [SC] [expires: 2027-04-12]
      80D1 5823 B7FD 1561 F9F7  BCDD DC30 D7C2 3CBB ABEE
uid           [ unknown] Debian Archive Automatic Signing Key (10/buster) <ftpmaster@debian.org>
sub   rsa4096 2019-04-14 [S] [expires: 2027-04-12]

/etc/apt/trusted.gpg.d/debian-archive-buster-security-automatic.gpg
-------------------------------------------------------------------
pub   rsa4096 2019-04-14 [SC] [expires: 2027-04-12]
      5E61 B217 265D A980 7A23  C5FF 4DFA B270 CAA9 6DFA
uid           [ unknown] Debian Security Archive Automatic Signing Key (10/buster) <ftpmaster@debian.org>
sub   rsa4096 2019-04-14 [S] [expires: 2027-04-12]

...

自分で作った鍵ペアのうち、公開鍵をgpg --exportでファイルにエクスポートし、HTTPサーバーに配置します。公開鍵ファイルをapt-key addで信頼済みの鍵束に追加します。

今回作成した鍵はテストが終わったら不要なのでapt-key del ’キーID’ で削除してください。apt-key listで出てきたキーIDをコピペすれば良いです(スペースもそのまま入れてOK)。

自作した鍵でReleaseファイルに署名する

最後にReleaseファイルに署名します。Releaseファイルの署名には2種類あって、署名をReleaseファイルと一緒に書くInReleaseファイルと、署名だけを別に書くRelease.gpgファイルがあります。

InReleaseだけ作成すれば機能するようですが、とりあえず両方の作り方を紹介しておきます。

Releaseの署名を作成する

### GnuPGでReleaseファイルに署名

# echo -n "abcd1234" | gpg --batch --passphrase-fd 0 --pinentry-mode loopback --clearsign -o InRelease Release
# echo -n "abcd1234" | gpg --batch --passphrase-fd 0 --pinentry-mode loopback -abs -o Release.gpg Release
# chmod 644 Release InRelease Release.gpg

署名が完了したらapt-get updateしてみましょう。

Releaseの署名を作成する
# apt-get update

Get:1 http://192.168.1.1/linux/debian buster InRelease [3941 B]
Hit:2 http://ftp.jp.debian.org/debian testing InRelease
Get:3 http://192.168.1.1/linux/debian buster/stable amd64 Packages [1752 B]
Get:4 http://192.168.1.1/linux/debian buster/stable amd64 Contents (deb) [1242 B]
Fetched 6935 B in 0s (25.7 kB/s)                               
Reading package lists... Done

うまくいきました。apt-get install docker-ceを実行すると、、、

apt-getを実行
# apt-get install docker-ce

Reading package lists... Done
Building dependency tree
Reading state information... Done
Package docker-ce is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
However the following packages replace it:
  docker-ce-cli

E: Package 'docker-ce' has no installation candidate

どうやら依存関係を無視してDockerのパッケージを1つしか登録しなかったため、依存関係のエラーが出てしまったようです。

他のパッケージ(docker-ce_cli, container.io)もダウンロードしましょう。pool/stable/amd64の下に追加し、apt-ftparchiveと署名をやり直します。

依存するパッケージを追加
linux
|-- conf
|   |-- apt_generate_debian_buster.conf
|   `-- apt_release_debian_buster.conf
`-- debian
    |-- dists
    |   `-- buster
    |       |-- InRelease
    |       |-- Release
    |       |-- Release.gpg
    |       |-- packages-amd64.db
    |       |-- pool
    |       |   `-- stable
    |       |       `-- amd64
    |       |           |-- containerd.io_1.2.6-3_amd64.deb
    |       |           |-- docker-ce-cli_19.03.1~3-0~debian-buster_amd64.deb
    |       |           `-- docker-ce_19.03.1~3-0~debian-buster_amd64.deb
    |       `-- stable
    |           |-- Contents-amd64
    |           |-- Contents-amd64.bz2
    |           |-- Contents-amd64.gz
    |           `-- binary-amd64
    |               |-- Packages
    |               |-- Packages.bz2
    |               `-- Packages.gz
    `-- gpg
        `-- public.key

10 directories, 16 files

以上のようなディレクトリ構成になるはずです。もう一度apt-get install docker-ceしてみましょう。

再びapt-getを実行
# apt-get install docker-ce

Reading package lists... Done
Building dependency tree 
Reading state information... Done
The following additional packages will be installed:
  aufs-dkms aufs-tools cgroupfs-mount containerd.io docker-ce-cli
Suggested packages:
  aufs-dev
The following NEW packages will be installed:
  aufs-dkms aufs-tools cgroupfs-mount containerd.io docker-ce docker-ce-cli
0 upgraded, 6 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/88.0 MB of archives.
After this operation, 390 MB of additional disk space will be used.
Do you want to continue? [Y/n]

Selecting previously unselected package aufs-dkms.
(Reading database ... 325385 files and directories currently installed.)
Preparing to unpack .../0-aufs-dkms_4.19+20190211-1_all.deb ...
Unpacking aufs-dkms (4.19+20190211-1) ...
Selecting previously unselected package aufs-tools.
Preparing to unpack .../1-aufs-tools_1%3a4.14+20190211-1_amd64.deb ...
Unpacking aufs-tools (1:4.14+20190211-1) ...
Selecting previously unselected package cgroupfs-mount.
Preparing to unpack .../2-cgroupfs-mount_1.4_all.deb ...
Unpacking cgroupfs-mount (1.4) ...
Selecting previously unselected package containerd.io.
Preparing to unpack .../3-containerd.io_1.2.6-3_amd64.deb ...
Unpacking containerd.io (1.2.6-3) ...
Selecting previously unselected package docker-ce-cli.
Preparing to unpack .../4-docker-ce-cli_5%3a19.03.1~3-0~debian-buster_amd64.deb ...
Unpacking docker-ce-cli (5:19.03.1~3-0~debian-buster) ...
Selecting previously unselected package docker-ce.
Preparing to unpack .../5-docker-ce_5%3a19.03.1~3-0~debian-buster_amd64.deb ...
Unpacking docker-ce (5:19.03.1~3-0~debian-buster) ...
Setting up aufs-tools (1:4.14+20190211-1) ...
Setting up containerd.io (1.2.6-3) ...
Created symlink /etc/systemd/system/multi-user.target.wants/containerd.service -> /lib/systemd/system/containerd.service.
Setting up docker-ce-cli (5:19.03.1~3-0~debian-buster) ...
Setting up aufs-dkms (4.19+20190211-1) ...
Loading new aufs-4.19+20190211 DKMS files...
Building for 4.19.0-5-amd64
Building initial module for 4.19.0-5-amd64
Done.

...

以上のようにapt-getもうまくいきました。良かった良かった。

編集者:すずき(2021/08/05 12:12)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年8月11日

独自のaptサーバー - その2 - apt-ftparchiveの設定、実行

目次: apt

WebサーバーあるいはFTPサーバーでDebianパッケージを配布する場合、*.debファイル以外にContents, Package, Releaseファイルが必要です。これらのファイルを作成するためのツールがapt-ftparchiveです。

今回はHTMLサーバーで配布することを考えます。Debianだと /var/wwwがルートディレクトリになっていることが多いと思います。以降 /var/wwwがルートディレクトリだとします。

ディレクトリ構成は前回紹介(2019年8月11日の日記参照)したDockerのディレクトリ構成に習うとします。Debianパッケージはどんなファイルでも良いです(後ほどテストするときのためamd64向けのパッケージのほうが良いです)が、今回はDockerのパッケージを1つダウンロードしてきて試します。

HTMLサーバーのルートディレクトリ、*.debファイルの置き場所
# cd /var/www

# tree linux

linux
|-- conf
|   |-- apt_generate_debian_buster.conf
|   `-- apt_release_debian_buster.conf
`-- debian
    `-- dists
        `-- buster
            |-- pool
            |   `-- stable
            |       `-- amd64
            |           `-- docker-ce_19.03.1~3-0~debian-buster_amd64.deb
            `-- stable
                `-- binary-amd64

9 directories, 3 files

Debianパッケージのみを配置した後のディレクトリ構造は上記のようになります。

apt-ftparchiveの設定ファイル

設定ファイルはapt_generate_debian_buster.confとapt_release_debian_buster.confと2つを使います。前者はディレクトリ構造を指定するファイルで、apt-ftparchive generateの引数に指定します。後者はリリース情報(ラベル、オリジナルなど)を指定するファイルで、apt-ftparchive releaseの -cオプションに指定します。

各設定ファイルの書き方を紹介します。

apt_generate_debian_buster.conf

Dir::ArchiveDir ".";
Dir::CacheDir   "dists/buster";
Default::Packages::Compress   ". gzip bzip2";
Default::Packages::Extensions ".deb";
Default::Sources::Compress    ". gzip bzip2";
Default::Contents::Compress   ". gzip bzip2";
Default::FileMode             0644;
TreeDefault::Directory        "dists/buster/pool/stable/amd64";
TreeDefault::Packages         "dists/buster/stable/binary-amd64/Packages";

Tree "dists/buster" {
    Sections "stable";
    Architectures "amd64";
};

BinDirectory "dists/buster/stable/binary-amd64" {
    Packages "dists/buster/stable/binary-amd64/Packages";
    Contents "dists/buster/stable/Contents-amd64";
};

この設定ファイルにはいくつかディレクトリパスが登場します。パスはapt-ftparchiveを実行するディレクトリ(/var/www/linux/buster)からの相対パスで記述します。

Tree::SectionsとTree::Architecturesは少し特殊で、ディレクトリパスの一部を構成します。{Tree}/{Sections} ディレクトリにContentsファイルが作成され、{Tree}/{Sections}/{Architectures} ディレクトリにPackagesファイルが作成されます。

apt_generate_debian_buster.confで複数のSectionsを指定

...

Tree "dists/buster" {
    Sections "stable testing";
    Architectures "amd64";
};

上記のようにTree::Sectionsには複数のセクションが指定でき、Tree::Architecturesには複数のアーキテクチャが指定できるはずですが、今のところTreeDefault::Packagesとの対応がよくわからず、使いこなせていません。複数のセクションを同時に指定する手段が見つかったら、また日記で書こうと思います。

apt_release_debian_buster.conf

APT::FTPArchive::Release {
    Architectures "amd64";
    Components "stable";
    Label "Test Label";
    Origin "Test";
    Suite "buster";
};

リリース情報を記述するファイルは上記のように書きます。APT::FTPArchive::Releaseには他のフィールドも記述できます。apt-ftparchiveのreleaseコマンドのヘルプ(リンク)によると「Origin, Label, Suite, Version, Codename, Date, NotAutomatic, ButAutomaticUpgrades, Acquire-By-Hash, Valid-Until, Signed-By, Architectures, Components, Description」が指定できるとのことですが、意味が説明されておらず、何を書くべきなのかわかりません……。

apt-ftparchiveの実行

設定ファイルを記述した後はapt-ftparchiveを実行して、Debianパッケージの情報について記述したContents, Packages, Releaseの各ファイルを作成します。

apt-ftparchiveを実行

# export TARGET=debian
# export DIST=buster
# export SECT=stable
# export ARCH=amd64
# mkdir -p /var/www/linux/${TARGET}/dists/${DIST}/${SECT}/binary-${ARCH}
# mkdir -p /var/www/linux/${TARGET}/dists/${DIST}/pool/${SECT}/${ARCH}


### *.debファイルをコピーする(モジュールによってコピー元は違うと思うので、これは一例)
### cp *.deb /var/www/linux/${TARGET}/dists/${DIST}/pool/${SECT}/${ARCH}


### Packages, Contentsファイルを作る
### linux/debianの下でapt-ftparchiveを実行しないと *.debが見つからないといわれる

# cd /var/www/linux/${TARGET}
# find . -name "Contents-*" -or -name "Contents-*.*" | xargs rm -f
# find . -name "Packages" -or -name "Packages.*" -or -name "packages-*" | xargs rm -f
# find . -name Release -or -name Release.gpg -or -name InRelease | xargs rm -f
# apt-ftparchive generate ../conf/apt_generate_${TARGET}_${DIST}.conf


### Releaseファイルを作る
### linux/debian/dists/busterの下でapt-ftparchiveを実行しないと、
### 後ほどapt-getを実行した際にパッケージが見つからないといわれる

# cd /var/www/linux/${TARGET}/dists/${DIST}
# apt-ftparchive release -c=../../../conf/apt_release_${TARGET}_${DIST}.conf . > Release

作成手順は以上のような感じですが、かなりパスに依存した動きで癖が強いです。正直言ってわかりにくいです。

apt-ftparchiveの実行後
# tree linux

linux
|-- conf
|   |-- apt_generate_debian_buster.conf
|   `-- apt_release_debian_buster.conf
`-- debian
   `-- dists
        `-- buster
            |-- Release
            |-- packages-amd64.db
            |-- pool
            |   `-- stable
            |       `-- amd64
            |           `-- docker-ce_19.03.1~3-0~debian-buster_amd64.deb
            `-- stable
                |-- Contents-amd64
                |-- Contents-amd64.bz2
                |-- Contents-amd64.gz
                `-- binary-amd64
                    |-- Packages
                    |-- Packages.bz2
                    `-- Packages.gz

コマンド実行後、Contents, Packages, Releaseファイルが生成され、上記のように配置されます。

独自aptサーバー完成ならず?

Contents, Packages, Releaseファイルがあればapt-getにaptサーバーとして認識してもらえるはずです。

/etc/apt/sources.listに独自aptサーバーを追加

deb [arch=amd64] http://192.168.1.1/linux/debian/ buster stable

適当なDebianマシンのaptの設定ファイルに、さきほど作成した独自aptサーバーを追加し apt-get updateを実行します。HTTPサーバーのIPアドレスは192.168.1.1とします。

独自aptサーバーに対してapt-getを実行
# apt-get update

Ign:1 http://192.168.1.1/linux/debian buster InRelease
Get:2 http://192.168.1.1/linux/debian buster Release [3233 B]
Ign:3 http://192.168.1.1/linux/debian buster Release.gpg
Hit:4 http://ftp.jp.debian.org/debian testing InRelease
Reading package lists... Done
E: The repository 'http://192.168.1.1/linux/debian buster Release' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.

残念ながらエラーになりました……。

Contents, Packages, Releaseファイルを作成しても終わりではありません。aptには悪意ある者がDebianパッケージを改変しても検知できる仕組みが搭載されていて、その対応をしないと「信用できないリポジトリ」だといわれてエラーになります。

(追記)下記が間違っていたので直しました。

apt_generate_debian_buster.confの修正

(誤)
TreeDefault::Directory        "dists/buster/pool/stable/stable/amd64";

(正)
TreeDefault::Directory        "dists/buster/pool/stable/amd64";
編集者:すずき(2021/08/05 12:12)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年8月10日

独自のaptサーバー - その1 - ディレクトリ構成

目次: apt

会社で独自のDebianパッケージを配布する際に、難しくてかなり困ったので、下調べの結果を兼ねてメモしておきます。

やりたいこととしては、独自に作成したDebianパッケージ(*.debファイル)を、

  • 複数のOS: Debian, Ubuntuなど
  • 複数の版: stable, testing, nightlyなど
  • 複数のアーキテクチャ: amd64, arm64など

この3つをどのように組み合わせても対応できるような、ディレクトリ構成と、aptサーバーの設定を作成することです。

Dockerが参考になる

ディレクトリ構成は、最初から考えるのは大変なので、参考としてDockerのaptリポジトリリンク)を見てみます。

Dockerのaptリポジトリサーバー
debian/
    dists/
        buster/ : Debian 10.0
            edge/ : なんだろ?
            nightly/ : 1日ごとにビルドされた版
            pool/ : *.debが入っているディレクトリ
            stable/ : 安定版
            test/ : テスト版?
        jessie/  : Debian 8.0
        stretch/ : Debian 9.0
        wheezy/  : Debian 7.0
    gpg : GnuPGの公開鍵、apt-keyで追加する

ubuntu/
    dists/
        artful/  : Ubuntu 17.10
        bionic/  : Ubuntu 18.04 LTS
        cosmic/  : Ubuntu 18.10
        disco/   : Ubuntu 19.04
        trusty/  : Ubuntu 14.04 LTS
        xenial/  : Ubuntu 16.04 LTS
        yakkety/ : Ubuntu 16.10
        zesty/   : Ubuntu 17.04
    gpg : GnuPGの公開鍵、apt-keyで追加する

こんな作りになっています。debian/distsもしくはubuntu/distsの下に各バージョンのコードネームが並んでいます。例えばdebian/dists/busterであればDebian 10.0用です。

コードネームのディレクトリの下には、各版stable, test用のディレクトリが並んでいます。poolディレクトリは版名ではなくて、パッケージファイル *.debを格納するディレクトリです。

Debian 10.0用のディレクトリ以下
debian/
    dists/
        buster/ : Debian 10.0
            edge/ : なんだろ?
            nightly/ : 1日ごとにビルドされた版
                binary-amd64/ : PC, 64bit用パッケージ情報
                    Packages   : パッケージ一覧
                binary-arm64/ : AArch64用パッケージ情報
                binary-armhf/ : AArch32用パッケージ情報
                Contents-amd64 : PC, 64bit用
                Contents-arm64 : AArch64用
                Contents-armhf : AArch32用
            pool/ : *.debが入っているディレクトリ
                edge/ : stableと同じ構成
                nightly/ : stableと同じ構成
                stable/
                    amd64/ : PC, 64bit用 *.deb
                    arm64/ : AArch64用 *.deb
                    armhf/ : AArch32用 *.deb
                test/ : stableと同じ構成
            stable/ : 安定版
            test/ : テスト版
            InRelease   : GnuPGの署名が追記されたReleaseファイル
            Release     : Contents, PackagesのSHAハッシュ一覧が書かれたファイル
            Release.gpg : GnuPGの署名だけ書かれたファイル

Debian向けとUbuntu向けはほぼ同じ構成です。

編集者:すずき(2021/08/05 12:11)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年7月30日

ヘッドフォンの謎のノイズ

オーディオは専門ではないし、神の耳も持っていないので、細かい音質うんぬんは全くわからないし、高級○○ケーブルなどはオカルトの一種とすら思っていますが……。

音質で唯一体験したことを思い出したので、メモしておきます。

以前はテレビのファーム開発をしていたため、職場ではテストのために少し良い(1万円〜2万円レベルの)ヘッドホン(SHURE SRH440-A)を使っていました。

何も鳴らしていないのに、ヘッドホンからたまにブーン……という微かなノイズと、バリ、バリ!という大きめのノイズが聞こえていました。

スマホとヘッドフォン

最初、評価ボードか機材の故障を疑っていたのですが、なんと原因は自分のスマホでした。

前者のブーン……ノイズは、ヘッドホンのケーブルをくるくると丸めて束ねた上に、スマホを置いていたため、スマホの電波を拾ってノイズになっていたようです。

たまにしか鳴らないのは、パケット通信のときしか強く電波を発しないからですかね?スマホを机の上に置かないようにしたらノイズは聞こえなくなりました。

家の安いヘッドホンで同じことをしても、ノイズは聞こえなかったので、感度の良いヘッドホンじゃないと拾わない(?)のかもしれません。

後者のバリバリ!ノイズは、ヘッドホンアンプの上にスマホを置きっぱにしたときに鳴っていました。ノイズを増幅するのか、かなり目立つバリバリ音が聞こえていました。

これもスマホとアンプを遠ざけて置くことで、ノイズが消えました。

謎が解ければ何てこと無い原因でしたけど、最初はわからなくて、このヘッドフォン壊れているんだろうか?不良品かしら……?とか思っていました。冤罪でした、ごめんねヘッドホンさん。

タチの悪い内蔵音源

音質でもう一つ思い出したのが、先代ノートPC(ThinkPad Edge E420)のアナログオーディオ出力は、常にシューシューというノイズが聞こえていたことです。

2010年は遥かに過ぎて、こんなにノイズが鳴るオーディオがあるはずない、聞き間違いだろうと思いきや、安物のオシロで見てもすぐわかるくらいノイズが載っていてショックでした。Conexantさん勘弁してよ……と思いました。

測定結果は、以前の日記に書いています(2014年10月18日の日記参照)。あれからもう五年も経ったのか。早いものだ。

メモ: 技術系?の話はFacebookから転記しておくことにした。リンクなどを追記。

編集者:すずき(2019/08/25 22:28)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年7月29日

RISC-V原典

RISC-V原典という本も買って読んでいます。どちらかというと頭から読む本ではなく、辞書的な本です。命令一覧の章はとても便利ですね。

RISC-V原典では「過去のアーキテクチャが患ったインクリメンタリズム」と他のアーキテクチャの複雑さを評していましたが、RISC-Vは出来たばかりなので「今」シンプルなのは当然だよね……などと思ったりしました。

RISC-Vと昔のARM

RISC-Vは命令セットの独自拡張を許しているため、同じRISC-V CPUを名乗っていても「A社CPUとB社CPUでは、同じバイナリが実行できない」ことがありえます。

ARMやx86も互換性のないCPUは存在しますが、共通の命令セットが大きいためあまり問題にはなりません。一方RISC-Vは共通命令セットが小さい(RV32I、MMUなしのマイコンレベル)ので、非互換性で問題が起きそうですね。ARMでいうとCortex-A系とCortex-M系を混ぜて売るようなもので、混乱を招きそうです……。

このタイプの命令拡張方式で私が思い出したのはARMです。ARMも昔はARMv5TEJのように、対応する拡張命令をアルファベットで追記する、似たような方式を採用していましたが、ARMv6で拡張命令に全て対応したため、拡張命令方式は消滅しました。

未来予想

私の予想としては、スマートフォン、デジタル家電、PCのような、比較的高性能な分野にはRV64GC(G = IMAFD、multiple, atomic, float, double)が共通命令セットになり、マイコン系にはRV32IかIMくらいが共通命令セットになる、辺りが落としどころかなと思います。

RISC-Vも「インクリメンタリズム」に陥る未来は避けられず、拡張に次ぐ拡張でゴチャゴチャになる未来を迎えると思いますが、20年後、

  • RISC-Vがそもそも使われているか
  • RISC-Vは今と同じことを言えるくらいシンプルを維持できるか
  • RISC-Vが別のアーキから同じ欠点を指摘されていないか(歴史は繰り返す…)

期待が大きいだけに、将来的にどうなるか、楽しみです。

編集者:すずき(2019/08/11 17:20)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年7月28日

強いオセロ

どうやっても圧勝してしまう「最弱オセロ」(リンク)が話題ですが、実はその横に「強いオセロ」リンク)もあります。URLから推測するにこちらの方が先に作られたように見えます。

名前に偽りはなく、ものすごく強いです。私のような素人の実力ですと50石(ほぼ真っ白)〜64石(全て白)で完敗します。終盤に一気にひっくり返され、全く勝てません。

まともにやっても全く勝てなかったので、どんな手でも良いから、1度でも勝てないだろうか?と試行錯誤するうちに、ちょっとしたクセが見えてきました。このAIは「終盤の大逆転」を重視していて、序盤〜中盤は石数が不利でも無視する傾向があります。

このクセを逆手に取り、中盤戦でとにかくゴリ押しして、白を全滅させる作戦を取ると、ごくたまに勝てることがあります。下記はその例です。


中盤でゴリ押しして勝てたケース

中盤で押し切れなければ負けです。20〜30局やりましたが、これ以外の勝ち方はできませんでした……。

編集者:すずき(2019/08/25 21:59)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年7月21日

RISC-Vの命令

目次: RISC-V

最近、何かと関わっているRISC-Vの理解のため、エミュレータを書いてみています。先日購入したHiFive Unleashed(2019年5月26日の日記参照)の1st ROMと2nd ROMを拝借して、Linuxがブートする辺りまで作るのが当面の目標です。

スクラッチから作ると辛いので、ARMv5のエミュレータememu(GitHubへのリンク)をベースにして改造して作っています。まがりなりにもARMv5が動いているんだから、RISC-Vも楽勝だろうと思いきや、世の中そんなに甘くありませんでした。

最初にコケたのはUnalignedな命令ロードです。RISC-VのC拡張をサポートする場合32bit境界ではないアドレスから、32bit命令をロードする場合があります。ARMv5ではUnalignedアクセス例外が発生します。

RISC-Vの命令エンコード

まだ完成していないので、現時点での感想ですが、RISC-Vの命令エンコードは比較的わかりやすい気がします。ただ、ブランチ命令のオフセットは、下記のような並びになっていて、不思議な配置です。


RISC-Vのブランチ命令

今まで見た中で一番見づらいものは、C拡張命令のバイナリです、これは異様に見づらいです。しかしC拡張の目的(命令長を削るため16bit長に無理して詰めている)からすると、仕方ないでしょうね。

編集者:すずき(2021/11/26 11:42)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年7月18日

C言語とCPUアーキテクチャと除算命令

目次: C言語とlibc

今まであまりCPUアーキテクチャの違いを感じたことはありませんが、除算命令を触っていたところ、アーキテクチャによってかなり動きが違っていて面白かったので、メモしておきます。

プログラムは下記のとおりです。

-1による除算

#include <stdio.h>
#include <limits.h>

void f(int a, int b)
{
        printf("mul:%08x * %08x = %08x\n", a, b, a * b);
        printf("div:%08x / %08 = %08x\n", a, b, a / b);
}

int main(int argc, char *argv[])
{
        f(INT_MAX, -1);
        f(INT_MIN + 1, -1);
        f(INT_MIN, -1);     //乗算、除算の動作は未定義
        f(INT_MAX, 0);      //除算の動作は未定義
}

初めに断っておくと、コメントを打った箇所については、C言語上の仕様上、動作が未定義です。つまり、どんなことでも起こり得ます。不定な結果が返ることもあるし、プログラムが停止することだってあります。

未定義動作も色々

このプログラムをx86 (x86_64, Ryzen 7 2700), ARM (AArch64, Cortex A53), RISC-V (RV64GC, SiFive FU540) のLinux上でそれぞれ実行してみます。

各アーキテクチャでの実行結果

#### x86_64 ####

mul:7fffffff * ffffffff = 80000001
div:7fffffff / ffffffff = 80000001
mul:80000001 * ffffffff = 7fffffff
div:80000001 / ffffffff = 7fffffff
mul:80000000 * ffffffff = 80000000
Floating point exception


#### AArch64 ####

mul:7fffffff * ffffffff = 80000001
div:7fffffff / ffffffff = 80000001
mul:80000001 * ffffffff = 7fffffff
div:80000001 / ffffffff = 7fffffff
mul:80000000 * ffffffff = 80000000
div:80000000 / ffffffff = 80000000
mul:7fffffff * 00000000 = 00000000
div:7fffffff / 00000000 = 00000000


#### RV64GC ####

mul:7fffffff * ffffffff = 80000001
div:7fffffff / ffffffff = 80000001
mul:80000001 * ffffffff = 7fffffff
div:80000001 / ffffffff = 7fffffff
mul:80000000 * ffffffff = 80000000
div:80000000 / ffffffff = 80000000
mul:7fffffff * 00000000 = 00000000
div:7fffffff / 00000000 = ffffffff

当然ながら、動作が定義されている演算は、どのアーキテクチャでも同じ結果です。当たり前ですね。

  • INT_MAX * (-1) = INT_MIN + 1
  • INT_MAX / (-1) = INT_MIN + 1
  • (INT_MIN + 1) * (-1) = INT_MAX
  • (INT_MIN + 1) / (-1) = INT_MAX
  • INT_MAX * 0 = 0

一方で動作が未定義の演算は、かなり挙動が変わります。

  • INT_MIN * (-1) = INT_MIN
  • INT_MIN / (-1) = クラッシュ (x86_64), INT_MIN (AArch64, RV64GC)
  • INT_MAX / 0 = クラッシュ (x86_64), 0 (AArch64), -1 (RV64GC)

個性が出ますね。

x86の除算命令の奇妙な仕様

先ほどの例でx86上でINT_MIN / (-1) の除算がクラッシュする原因はidiv命令の仕様です。

Intelの命令仕様書(Intel Architectures Software Developer Manual: Vol 2)のIDIV - Signed Divideのページを見ると、保護モード例外 #DEが発生する条件として、

  • ソース・オペランド(除数)が0である場合
  • デスティネーションに対して符号付きの結果(商)が大きすぎる場合

この2条件が挙げられています。INT_MIN / (-1) は結果が32bitで表現できないため、後者に引っ掛かるわけです。

異常な演算に対して例外を発生させる設計思想なら分かりますが、乗算命令は異常な結果でも素通しなのに、除算命令は異常な結果だと例外発生します。片手落ちの不思議な仕様です。変なの……。

編集者:すずき(2023/08/19 19:34)

コメント一覧

  • hdkさん(2019/07/20 00:23)
    x86の除算例外は8086/8088の頃からありました。乗算については、8ビット同士を掛けて16ビットを出すか、16ビット同士を掛けて32ビットを出すかしかなかったので、異常な結果というのがそもそもなかったんですよね。(下位ビットだけ使うのはCコンパイラーの勝手なので。) 今はIMUL命令のオペランドが増えて同一ビット幅の答えを返す命令もありますが、例外がないのは名残か、あるいは、同じく例外がないシフトと足し算の命令の代わりに使われることを意図したかでしょうか。想像ですが。
  • すずきさん(2019/07/20 10:56)
    MUL については、結果が倍のビット幅になっていたからという理屈もわかるんですが、加算、減算はオーバーフローしたらOFをセットするだけなのに、「除算だけ」オーバーフローで例外を発生させるのは、変な仕様です。。。
  • すずきさん(2019/07/20 11:02)
    OFをセットして例外を出したければINTOでオーバーフロー例外(#OF)を発生させるのがx86の仕様に思えるのですが、除算だけ特別というかわざわざ除算例外(#DE)なんて用意しているのも不思議です……。
  • hdkさん(2019/07/24 07:25)
    加算減算は符号のありなしどちらも命令が同じですから、オーバーフローで即例外ってわけにはいかないですね。まぁ確かに除算も不正な解を出してフラグを立てる実装もありそうですが、除算回路が止まっちゃうのかなーという気も... ちなみにAAM命令でも0を指定すれば#DE発生させられます。
  • すずきさん(2019/07/24 22:22)
    AAM(ASCII Adjust AX After Multiply)って使ったことないですが、乗算系の命令でも #DE 発生するんですね。
    一貫性が無い感じが x86 らしいといえばらしいです。。。
  • hdkさん(2019/07/25 00:02)
    あっ、AAMはマニュアルのオペレーションを見ていただくとわかりますが中身は除算命令ですので、乗算系とは言えない気がします。DIV命令と違って8ビットを8ビットで割って8ビットの商と余りを出すので(全部符号なし整数)、0除算以外に例外が発生する条件はありません。
open/close この記事にコメントする



link もっと前
2019年8月12日 >>> 2019年7月16日
link もっと後

管理用メニュー

link 記事を新規作成

<2019>
<<<08>>>
----123
45678910
11121314151617
18192021222324
25262728293031

最近のコメント5件

  • link 02年8月4日
    lxbfYeaaさん (07/12 10:11)
    「555」
  • link 24年6月17日
    すずきさん (06/23 00:12)
    「ありがとうございます。バルコニーではない...」
  • link 24年6月17日
    hdkさん (06/22 22:08)
    「GPSの最初の同期を取る時は見晴らしのい...」
  • link 24年5月16日
    すずきさん (05/21 11:41)
    「あー、確かにdpkg-reconfigu...」
  • link 24年5月16日
    hdkさん (05/21 08:55)
    「システム全体のlocale設定はDebi...」

最近の記事3件

  • link 24年8月10日
    すずき (08/12 16:23)
    「[Linuxを調べる - initrdとカーネル引数] 目次: Linux今どき(?)のinitrdとカーネル引数の渡し方を知...」
  • link 23年4月10日
    すずき (08/12 15:08)
    「[Linux - まとめリンク] 目次: Linuxカーネル、ドライバ関連。Linuxのstruct pageって何?Linu...」
  • link 24年8月5日
    すずき (08/11 23:27)
    「[debootstrapと他アーキテクチャバイナリとbinfmt_misc] 目次: Linux以前、Debianのrootf...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 08/12 16:23