Arm64仮想マシンの作成 (2015/08/16)

前回は Arm64 のシングルボードコンピュータ(SBC) である Dragonboard 410C を紹介しましたが、「実機を入手するまでもないよ」と考えている人向けに Arm64 の仮想マシンの作り方を紹介します。

Arm64 というのは通称のようなもので、正式には「'''ARMv8''' アーキテクチャの '''AArch64''' 実行状態をサポートする '''A64''' 命令セット」といった表現が正しいようですが、分かり難いので Arm64 で行きます。Arm64 のアセンブリプログラミングをしてみたくて、Dragonboard 410C を入手しましたが、Raspberry Pi と違って、まだほとんど普及していないようです。 CPUの違いはCコンパイラが吸収してくれるため、Linux が動作さえすれば動作速度や消費電力が違うぐらいでほとんどの人には関係ありません。 それでも新しいマシンが手に入れば色々探ってみたくなります。 Arm64の実機を持っていない人のために Arm64 の仮想サーバで Arm64用の Ubuntu 15.04 を動作させることにします。 ちょっと長い道のりですが、NetworkManager やら、systemd やら色々と最近の Linux の常識の変化を味わうことができます。 面倒な人は サクッとHikey とか Dragonboard 410Cなど を買ってしまいましょう。


ホストマシンとしてはちょっと古いですが、Core2Duo (2.66GHz) のマシンに新たに ubuntu-15.04-desktop-amd64 をインストールしました。Ubuntu 15.04 (Vivid Vervet) のインストールの方法は アチコチ で解説されているので省略します。


デスクトップ版には sshd がインストールされていないので、openssh-server をインストールしました。

jun@ubuntu1504:~$ sudo apt install openssh-server
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下の追加パッケージがインストールされます:
  libck-connector0 ncurses-term openssh-sftp-server ssh-import-id
提案パッケージ:
  rssh molly-guard monkeysphere
以下のパッケージが新たにインストールされます:
  libck-connector0 ncurses-term openssh-server openssh-sftp-server
  ssh-import-id
アップグレード: 0 個、新規インストール: 5 個、削除: 0 個、保留: 207 個。
639 kB のアーカイブを取得する必要があります。
この操作後に追加で 3,498 kB のディスク容量が消費されます。
続行しますか? [Y/n] y

Arm64 用QEMU をインストール

Arm64 用の仮想マシンエミュレータは qemu-system-aarch64 です。パッケージ名に qemu-system-aarch64 を指定しても qemu-system-arm がインストールされるようです。

jun@ubuntu1504:~$ sudo apt install qemu-system-aarch64
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
注意、'qemu-system-aarch64' の代わりに 'qemu-system-arm' を選択しています
以下の追加パッケージがインストールされます:
  ipxe-qemu libboost-thread1.55.0 libfdt1 librados2 librbd1 libsdl1.2debian
  libseccomp2 libusbredirparser1 libxen-4.5 libxenstore3.0 qemu-system-common
  qemu-utils sharutils
提案パッケージ:
  vde2 debootstrap bsd-mailx mailx
以下のパッケージが新たにインストールされます:
  ipxe-qemu libboost-thread1.55.0 libfdt1 librados2 librbd1 libsdl1.2debian
  libseccomp2 libusbredirparser1 libxen-4.5 libxenstore3.0 qemu-system-arm
  qemu-system-common qemu-utils sharutils
アップグレード: 0 個、新規インストール: 14 個、削除: 0 個、保留: 15 個。
7,454 kB のアーカイブを取得する必要があります。
この操作後に追加で 33.2 MB のディスク容量が消費されます。
続行しますか? [Y/n] y
:
略
:

インストールされた qemu 関連のパッケージを確認します。

$ dpkg -l |grep qemu
ii  ipxe-qemu           1.0.0+git-20141004.86285d1-1ubuntu3 all   PXE boot firmware - ROM images for qemu
ii  qemu-system-arm     1:2.2+dfsg-5expubuntu9.3            amd64 QEMU full system emulation binaries (arm)
ii  qemu-system-common  1:2.2+dfsg-5expubuntu9.3            amd64 QEMU full system emulation binaries (common files)
ii  qemu-utils          1:2.2+dfsg-5expubuntu9.3            amd64 QEMU utilities

インストールされた qemu のコマンドを確認します。

jun@ubuntu1504:~$ ls -l /usr/bin/qemu*
-rwxr-xr-x 1 root root  884576 Jul 28 04:27 /usr/bin/qemu-img
-rwxr-xr-x 1 root root  939928 Jul 28 04:27 /usr/bin/qemu-io
-rwxr-xr-x 1 root root  860640 Jul 28 04:27 /usr/bin/qemu-nbd
-rwxr-xr-x 1 root root 6752176 Jul 28 04:27 /usr/bin/qemu-system-aarch64
-rwxr-xr-x 1 root root 6530992 Jul 28 04:27 /usr/bin/qemu-system-arm

qemu のバージョンを確認します。

$ qemu-system-aarch64 -version
QEMU emulator version 2.2.0 (Debian 1:2.2+dfsg-5expubuntu9.3),
 Copyright (c) 2003-2008 Fabrice Bellard

Arm の 64 ビット版の CPU である cortex-a57 がサポートされていることを確認します。

$ qemu-system-aarch64 -cpu help -machine virt
Available CPUs:
  arm1026
  arm1136
  arm1136-r2
  arm1176
  arm11mpcore
  arm926
  arm946
  cortex-a15
  cortex-a57
  cortex-a8
  cortex-a9
  cortex-m3
  pxa250
  pxa255
  pxa260
  pxa261
  pxa262
  pxa270-a0
  pxa270-a1
  pxa270
  pxa270-b0
  pxa270-b1
  pxa270-c0
  pxa270-c5
  sa1100
  sa1110
  ti925t

Arm64 システムのエミュレータとして qemu-system-aarch64 が使えることを確認できました。 仮想マシンが用意出来たので、Arm64用のLinuxをインストールしましょう。

Arm64用 Ubuntu イメージの入手

Arm64用 Ubuntu のディスクイメージは https://cloud-images.ubuntu.com/vivid/current/ から入手できます。私は 2015/08/12 版のディスクイメージをダウンロードしました。

vivid-server-cloudimg-arm64-disk1.img         07-Aug-2015 08:16  348M

作業用のディレクトリとして、ホームディレクトリ(/home/jun) の下に qemuarm64 というディレクトリを作成して、そこにディスクイメージを置きました。

jun@ubuntu1504:~$ mkdir qemuarm64
jun@ubuntu1504:~/qemuarm64$ mv ../vivid-server-cloudimg-arm64-disk1.img .
jun@ubuntu1504:~/qemuarm64$ ls -lt
total 356516
-rw-rw-r-- 1 jun jun 364708352 Aug 12 18:14 vivid-server-cloudimg-arm64-disk1.img

initrd と カーネルの取得

QEMU でディスクイメージから Linux を起動するため、カーネル (vmlinuz) とイニシャル RAM ディスクイメージ(initrd.img) をQEMU のコマンドラインから指定する必要があります。 vmlinuz と initrd.img を Ubuntu のArm64用ディスクイメージ(vivid-server-cloudimg-arm64-disk1.img) から取り出します。 Ubuntuのディスクイメージをマウントするために qemu-nbd を使用します。先ほど作成した qemuarm64 ディレクトリ内で作業することにします。マウントポイントとして qemuarm64/mnt というディレクトリを作ります。

$ sudo modprobe nbd max_part=63
$ sudo qemu-nbd -c /dev/nbd0 vivid-server-cloudimg-arm64-disk1.img
$ mkdir mnt
$ sudo mount /dev/nbd0p1 mnt

これで、カレントディレクトリ (qemuarm64) の mnt ディレクトリ以下にUbuntu のArm64用ディスクイメージの内容が見えるようになります。

jun@ubuntu1504:~/qemuarm64$ ls -lt mnt/

drwxr-xr-x 95 root root  4096 Aug  7 16:58 etc
drwx------  2 root root 16384 Aug  7 16:40 lost+found
drwxrwxrwt  2 root root  4096 Aug  7 16:40 tmp
drwxr-xr-x  2 root root  4096 Aug  7 16:40 sbin
drwxr-xr-x  2 root root  4096 Aug  7 16:40 bin
drwxr-xr-x 12 root root  4096 Aug  7 16:40 var
drwxr-xr-x  3 root root  4096 Aug  7 16:40 boot
drwx------  2 root root  4096 Aug  7 16:39 root
drwxr-xr-x  2 root root  4096 Aug  7 16:38 run
lrwxrwxrwx  1 root root    33 Aug  7 16:36 initrd.img -> boot/initrd.img-3.19.0-25-generic
lrwxrwxrwx  1 root root    30 Aug  7 16:36 vmlinuz -> boot/vmlinuz-3.19.0-25-generic
drwxr-xr-x 22 root root  4096 Aug  7 16:33 lib
drwxr-xr-x  4 root root  4096 Aug  7 16:31 dev
drwxr-xr-x 10 root root  4096 Aug  7 16:22 usr
drwxr-xr-x  2 root root  4096 Aug  7 16:22 media
drwxr-xr-x  2 root root  4096 Aug  7 16:22 opt
drwxr-xr-x  2 root root  4096 Aug  7 16:22 srv
drwxr-xr-x  2 root root  4096 Apr 18 06:38 home
drwxr-xr-x  2 root root  4096 Apr 18 06:38 mnt
drwxr-xr-x  2 root root  4096 Apr 18 06:38 proc
drwxr-xr-x  2 root root  4096 Apr  7 03:44 sys

必要なファイルが boot/initrd.img-3.19.0-25-generic と boot/vmlinuz-3.19.0-25-generic であることが確認できました。これらのファイルを qemuarm64(カレントディレクトリ) にコピーします。

$ sudo cp mnt/boot/vmlinuz-3.19.0-25-generic .
$ sudo cp mnt/boot/initrd.img-3.19.0-25-generic .

マウントした Arm64 用ディスクイメージをアンマウントします。

$ sudo umount mnt
$ sudo qemu-nbd -d /dev/nbd0
/dev/nbd0 disconnected

ファイルを確認

コピーしたファイルを確認します。

$ ls -lt

-rw-r--r--  1 root root  17025801 Aug 12 19:23 initrd.img-3.19.0-25-generic
-rw-------  1 root root  12197888 Aug 12 19:22 vmlinuz-3.19.0-25-generic
-rw-rw-r--  1 jun  jun  365035520 Aug 12 19:22 vivid-server-cloudimg-arm64-disk1.img
drwxr-xr-x 21 root root      4096 Aug  7 16:40 mnt

initrd.img-3.19.0-25-generic と vmlinuz-3.19.0-25-generic の所有者が root になっているため、自分に変更しておきます。

jun@ubuntu1504:~/qemuarm64$ sudo chown jun:jun *-generic
jun@ubuntu1504:~/qemuarm64$ ls -lt
total 385360
-rw-rw-r--  1 jun  jun  365035520 Aug 12 19:23 vivid-server-cloudimg-arm64-disk1.img
-rw-rw-rw-  1 jun  jun   17025801 Aug 12 19:23 initrd.img-3.19.0-25-generic
-rw-rw-rw-  1 jun  jun   12197888 Aug 12 19:22 vmlinuz-3.19.0-25-generic
drwxr-xr-x 21 root root      4096 Aug  7 16:40 mnt

Arm64 用 Ubuntu を起動してみる

これだけでArm64 用 Ubuntu を起動することができます。ネットワーク等の設定は後にしてとりあえず起動してみましょう。 コマンドはqemu-system-aarch64 ですが引数が非常に長いです。次の行をすべてコピーして、コンソールの画面に貼りつけて下さい。以下のオプションでは管理者権限は不要なので sudo する必要はありません。5行目でユーザ「ubuntu」のパスワードを「upass」と指定しています。

qemu-system-aarch64 -m 1024 -cpu cortex-a57 -nographic -machine virt \
 -kernel vmlinuz-3.19.0-25-generic \
 -append 'root=/dev/vda1 rw rootwait mem=1024M console=ttyS0 \
  console=ttyAMA0,38400n8 init=/usr/lib/cloud-init/uncloud-init \
  ds=nocloud ubuntu-pass=upass' \
 -drive if=none,id=image,file=vivid-server-cloudimg-arm64-disk1.img \
 -initrd initrd.img-3.19.0-25-generic \
 -device virtio-blk-device,drive=image \
 -netdev user,id=user0 \
 -device virtio-net-device,netdev=user0

画面上に次のように表示されるはずです。ログインできるまで数分かかります。

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Initializing cgroup subsys cpuset
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Initializing cgroup subsys cpuacct
[    0.000000] Linux version 3.19.0-25-generic (buildd@auburn) 
    (gcc version 4.9.2 (Ubuntu/Linaro 4.9.2-10ubuntu13) ) #26-Ubuntu SMP 
    Fri Jul 24 21:23:02 UTC 2015 (Ubuntu 3.19.0-25.26-generic 3.19.8-ckt2)
[    0.000000] CPU: AArch64 Processor [411fd070] revision 0
[    0.000000] Detected PIPT I-cache on CPU0
[    0.000000] alternatives: enabling workaround for ARM erratum 832075
[    0.000000] Memory limited to 1024MB
[    0.000000] efi: Getting EFI parameters from FDT:
[    0.000000] efi: UEFI not found.
[    0.000000] psci: probing for conduit method from DT.
[    0.000000] psci: PSCIv0.2 detected in firmware.
[    0.000000] psci: Using standard PSCI v0.2 function IDs
:
略
:
Ubuntu 15.04 ubuntu ttyAMA0

ubuntu login: ubuntu
Password: 
Last login: Mon Feb 16 21:01:04 UTC 2015 on ttyAMA0
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@ubuntu:~$ 

ユーザ名は「ubuntu」、パスワードはコマンドラインで指定した「upass」です。パスワードは qemu-system-aarch64 コマンドの引数で変更できます。これで普通に Linux が動作します。x86_64 なマシン上の kvm と異なり、 Arm64 はソフトウェアのエミュレータとして動作します。 しかし、コマンドラインで使う上では特に遅く感じること無く動作します。

ちょっとゲスト上 (Arm64 用 Ubuntu) でコマンドを試してみましょう。

ubuntu@ubuntu:/$ uname -a
Linux ubuntu 3.19.0-25-generic #26-Ubuntu SMP Fri Jul 24 21:23:02 UTC 2015 aarch64 aarch64 aarch64 GNU/Linux

ubuntu@ubuntu:/$ cat /proc/cpuinfo 
processor : 0
Features  : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x1
CPU part  : 0xd07
CPU revision  : 0

ubuntu@ubuntu:/$ ps ax
略
  280 ?        Ss     0:04 /lib/systemd/systemd-journald
  290 ?        Ss     0:01 /lib/systemd/systemd-udevd
  391 ?        Ssl    0:01 /lib/systemd/systemd-timesyncd
  601 ?        Ss     0:00 /usr/sbin/atd -f
  606 ?        Ssl    0:01 /usr/lib/accountsservice/accounts-daemon
  608 ?        Ss     0:00 /lib/systemd/systemd-logind
  614 ?        Ssl    0:01 /usr/sbin/rsyslogd -n
  624 ?        Ss     0:00 /usr/sbin/cron -f
  634 ?        Ss     0:00 /usr/bin/dbus-daemon --system --address=systemd: --no
  673 ?        Ssl    0:00 /usr/lib/policykit-1/polkitd --no-debug
  789 ?        Ss     0:00 /usr/sbin/sshd -D
  795 ?        Ss     0:00 /bin/login --       
  796 tty1     Ss+    0:00 /sbin/agetty --noclear tty1 linux
  811 ?        S      0:00 [kworker/u2:2]
  895 ?        Ss     0:00 /lib/systemd/systemd --user
  897 ?        S      0:00 (sd-pam)  
  899 ttyAMA0  S      0:01 -bash
  923 ?        S      0:00 [kworker/0:1]
  928 ttyAMA0  R+     0:00 ps ax

ネットワークの状態を調べてみます。これもゲスト上 (Arm64 用 Ubuntu) での作業です。

ubuntu@ubuntu:~$ ifconfig -a
eth0      Link encap:Ethernet  HWaddr 52:54:00:12:34:56  
          inet addr:10.0.2.15  Bcast:10.0.2.255  Mask:255.255.255.0
          inet6 addr: fe80::5054:ff:fe12:3456/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:64 errors:0 dropped:0 overruns:0 frame:0
          TX packets:73 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:24638 (24.6 KB)  TX bytes:6515 (6.5 KB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:160 errors:0 dropped:0 overruns:0 frame:0
          TX packets:160 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:12960 (12.9 KB)  TX bytes:12960 (12.9 KB)

ubuntu@ubuntu:~$ 

ip アドレスが 10.0.2.15 になっていますが、ホスト(qemu-system-aarch64 コマンドを実行した実機)がインターネットに接続できる状態ならば、Arm64の仮想PCからもネットワークに接続できます。https://google.com/のファイルを取得してみます。

ubuntu@ubuntu:~$ wget https://google.com/
--2015-08-12 12:17:32--  https://google.com/
Resolving google.com (google.com)... 216.58.221.206, 2404:6800:400a:805::200e
Connecting to google.com (google.com)|216.58.221.206|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://www.google.co.jp/?gfe_rd=cr&ei=XDnLVaa7IcfD8Ae9qKy4Bw>[following]
--2015-08-12 12:17:32--  https://www.google.co.jp/?gfe_rd=cr&ei=XDnLVaa7IcfD8Ae9qKy4Bw
Resolving www.google.co.jp (www.google.co.jp)... 173.194.117.175, 173.194.117.183, 173.194.117.184, ...
Connecting to www.google.co.jp (www.google.co.jp)|173.194.117.175|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘index.html’

index.html              [ <=>                  ]  18.44K  --.-KB/s   in 0.003s 

2015-08-12 12:17:32 (7.08 MB/s) - ‘index.html’ saved [18882]

ubuntu@ubuntu:~$ ls -l
total 20
-rw-rw-r-- 1 ubuntu ubuntu 18882 Aug 12 12:17 index.html

無事にインターネットに接続できることが確認できました。しかしLAN内の別のマシンから仮想サーバにはアクセスできません。これを可能にするには後述のブリッジの設定が必要です。

終了

qemu-system-aarch64 コマンドを終了するには、仮想マシンの中(ゲスト)で shutdown を実行します。 仮想マシンのOSが停止すると qemu-system-aarch64 コマンド自体も終了します。 または、qemu-system-aarch64 コマンドのモニター機能を使って終了することもできます。コントロールを押しながらAキーを押した後、C を押すと、 (qemu) と表示されます。ここで q を押すとqemu-system-aarch64 コマンドは終了します。モニター機能からの終了は、仮想マシンからすると電源を突然止められたようなものなので shutdown したほうがいいかもしれません。何らかの理由で仮想マシンのOSがフリーズしてもモニター機能からの終了は可能です。

ubuntu@ubuntu:~$ sudo shutdown -h now
sudo: unable to resolve host ubuntu
PolicyKit daemon disconnected from the bus.
We are no longer a registered authentication agent.
[ 1192.928198] reboot: Power down
jun@ubuntu1504:~/qemuarm64$ 

Arm64 仮想サーバの構築

LAN内の別のマシンから実機のサーバのようにネットワーク越しにアクセスできるようにするためには、仮想サーバをホストマシンに作成したブリッジを介して接続する必要があります。ホストマシン側のネットワークの設定を変更します。

ブリッジ

ブリッジとは Ethernet Bridge のことで、物理的には普通のスイッチングハブ(レイヤー2スイッチ)と考えることができます。 ホストマシンの内部に仮想的にスイッチングハブ(ブリッジ)を用意して、ホストもゲスト(仮想マシン)もそのハブに繋ぐイメージです。 通常はPCのネットワークカード(NIC)は自分宛のEthernetフレーム(IP層より1つ下のデータリンク層)だけを受付けて、別マシン宛のフレームは無視します。 しかし仮想マシン宛のフレームも取り込むために、ホストマシンのネットワークカードを宛先に関係なくEthernetフレームを受け付けるプロミスキャスモード(promiscuous mode)に変更します。プロミスキャスモードにすることでEthernetフレームの宛先MACアドレスが自分と異なる場合でも読み込むことができるため、スイッチングハブ(ブリッジ)として動作できるようになります。


ホスト内にブリッジを生成して、eth0をブリッジに繋ぎかえます。 bridge-utils パッケージに含まれるコマンドを使って 「brctl addbr ブリッジ名」で生成できます。


bridge-utils のインストール

ホストマシンの Ubuntu 15.04 にbridge-utils をインストールします。

jun@ubuntu1504:~/qemuarm64$ sudo apt install bridge-utils
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  bridge-utils
0 upgraded, 1 newly installed, 0 to remove and 15 not upgraded.
Need to get 29.1 kB of archives.
After this operation, 146 kB of additional disk space will be used.
Get:1 https://jp.archive.ubuntu.com/ubuntu/vivid/main bridge-utils amd64 1.5-7ubuntu1 [29.1 kB]
Fetched 29.1 kB in 0s (198 kB/s)

ブリッジの追加

ブリッジを生成して、eth0を繋ぎかえる時にネットワークは一旦切断されるため、シェルスクリプトにしておけばリモートからでも連続してコマンドを実行できます。ブリッジにIPアドレスを設定するとホストも外部ネットワークに接続できます。ネットワークは一旦切断されるため、リモートからSSHで接続している場合は再接続する必要があります。


次に示す「set_bridge.sh」では Ubuntu15.04 のNetworkManager がデフォルトで設定する "Wired connection 1" を削除した後に、ブリッジを追加し、ブリッジのIPアドレスを 172.18.21.80 に、ゲートウェイを 172.18.21.1 、DNSを 172.18.21.1 に設定するスクリプトなっています。 eth0 は "Wired connection 1" から "eth0" に名称を変更しています。 私は成り行き上、クラスBのプライベートIPアドレス (172.16.0.0 - 172.31.255.255) を使っていますが、クラスC (192.168.0.0 - 192.168.255.255) の範囲が普通ではないかと思います。 各自のネットワーク環境にあわせて変更してください。「sudo sh ./set_bridge.sh」で実行できます。NetworkManager のコマンドラインクライアントの nmcli コマンドを使います。 Ubuntu + KVM で仮想サーバ で行っているような /etc/network/interfaces を編集する古い方法はもう使いません。nmcli コマンドは非常に豊富な機能を持っています。「man nmcli」で1000行以上のマニュアルが読めます。

jun@ubuntu1504:~$ cat set_bridge.sh
#!/bin/sh

# eth0 を削除
 nmcli connection delete "Wired connection 1"

# ブリッジを追加
 nmcli connection add type bridge \
  autoconnect yes \
  ifname      br0 \
  con-name    br0

# ブリッジのIPアドレスを設定
 nmcli connection modify br0 \
  ipv4.method manual    ipv4.addresses "172.18.21.80/24 172.18.21.1" \
  ipv4.dns 172.18.21.1  ipv6.method ignore bridge.stp no

# eth0 を作成
 nmcli connection add type bridge-slave \
   autoconnect yes \
   ifname eth0 \
   con-name eth0 \
   master br0

ブリッジを削除する方法

元に戻すためのスクリプトも用意しておきます。 ブリッジを削除して、DHCPで自動設定するデフォルトの動作に戻ります。

jun@ubuntu1504:~$ cat reset_bridge.sh 
#!/bin/sh

# ブリッジの削除
nmcli connection delete "br0"
nmcli connection delete "eth0"

# 通常の eth0 を作成
nmcli connection add type ethernet \
  ifname eth0 \
  con-name "Wired connection 1" \
  autoconnect yes

nmcli connection modify "Wired connection 1" \
  ipv4.method auto

実際にブリッジの作成と削除ができることを確認してみます。ブリッジの固定IPとして 172.18.21.80 が、DHCPに振られるIPとして 172.18.21.14 になっていることが確認できます。以下の操作はホストマシンで直接操作して記録しました。ssh のリモート接続では IPが切り替わった時点で表示が停止するためです。切り替わった新しい IPアドレスに対して接続し直せばアクセスできます。

jun@ubuntu1504:~$ sudo sh -x ./set_bridge.sh ; ifconfig
+ nmcli connection delete Wired connection 1
+ nmcli connection add type bridge autoconnect yes ifname br0 con-name br0

(process:6945): libnm-glib-WARNING **: async_got_type: could not read properties
 for /org/freedesktop/NetworkManager/ActiveConnection/21: Method "Get" with 
signature "ss" on interface "org.freedesktop.DBus.Properties" doesn't exist

Connection 'br0' (f7454081-6178-4acd-916c-f111b3958704) successfully added.
+ nmcli connection modify br0 ipv4.method manual ipv4.addresses 172.18.21.80/24 172.18.21.1
   ipv4.dns 172.18.21.1 ipv6.method ignore bridge.stp no
+ nmcli connection add type bridge-slave autoconnect yes ifname eth0 con-name eth0 master br0
Connection 'eth0' (dffbb94d-4b99-41ac-93c6-bd205fec0283) successfully added.

br0       Link encap:イーサネット  ハードウェアアドレス 00:1d:60:6d:ae:b4  
          inetアドレス:172.18.21.80 ブロードキャスト:172.18.21.255 マスク:255.255.255.0
          UP BROADCAST MULTICAST  MTU:1500  メトリック:1
          RXパケット:0 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:0 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:0 
          RXバイト:0 (0.0 B)  TXバイト:0 (0.0 B)

eth0      Link encap:イーサネット  ハードウェアアドレス 00:1d:60:6d:ae:b4  
          UP BROADCAST RUNNING MULTICAST  MTU:1500  メトリック:1
          RXパケット:2421116 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:1209100 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:1000 
          RXバイト:583618646 (583.6 MB)  TXバイト:821306211 (821.3 MB)
          割り込み:17 

lo        Link encap:ローカルループバック  
          inetアドレス:127.0.0.1  マスク:255.0.0.0
          inet6アドレス: ::1/128 範囲:ホスト
          UP LOOPBACK RUNNING  MTU:65536  メトリック:1
          RXパケット:7615 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:7615 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:0 
          RXバイト:935140 (935.1 KB)  TXバイト:935140 (935.1 KB)

jun@ubuntu1504:~$ sudo sh -x ./reset_bridge.sh ; ifconfig
+ nmcli connection delete br0
+ nmcli connection delete eth0
+ nmcli connection add type ethernet ifname eth0 con-name Wired connection 1 autoconnect yes
Connection 'Wired connection 1' (8026e5c6-4230-46cc-b1d4-c70c3be920ab) successfully added.
+ nmcli connection modify Wired connection 1 ipv4.method auto

eth0      Link encap:イーサネット  ハードウェアアドレス 00:1d:60:6d:ae:b4  
          inetアドレス:172.18.21.14 ブロードキャスト:172.18.21.255 マスク:255.255.255.0
          inet6アドレス: fe80::21d:60ff:fe6d:aeb4/64 範囲:リンク
          UP BROADCAST RUNNING MULTICAST  MTU:1500  メトリック:1
          RXパケット:2421117 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:1209106 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:1000 
          RXバイト:583619236 (583.6 MB)  TXバイト:821307143 (821.3 MB)
          割り込み:17 

lo        Link encap:ローカルループバック  
          inetアドレス:127.0.0.1  マスク:255.0.0.0
          inet6アドレス: ::1/128 範囲:ホスト
          UP LOOPBACK RUNNING  MTU:65536  メトリック:1
          RXパケット:7644 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:7644 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:0 
          RXバイト:936929 (936.9 KB)  TXバイト:936929 (936.9 KB)

jun@ubuntu1504:~$ sudo sh -x ./set_bridge.sh ; ifconfig
+ nmcli connection delete Wired connection 1
+ nmcli connection add type bridge autoconnect yes ifname br0 con-name br0

(process:7414): libnm-glib-WARNING **: async_got_type: could not read properties 
  for /org/freedesktop/NetworkManager/ActiveConnection/24: Method "Get" 
  with signature "ss" on interface "org.freedesktop.DBus.Properties" doesn't exist

Connection 'br0' (c1ce8f9c-6b44-4490-9eff-63c4d1f2a191) successfully added.
+ nmcli connection modify br0 ipv4.method manual ipv4.addresses 172.18.21.80/24 172.18.21.1
   ipv4.dns 172.18.21.1 ipv6.method ignore bridge.stp no
+ nmcli connection add type bridge-slave autoconnect yes ifname eth0 con-name eth0 master br0
Connection 'eth0' (330554d0-c11e-46b7-9705-0de9c42c6a7c) successfully added.

br0       Link encap:イーサネット  ハードウェアアドレス 00:1d:60:6d:ae:b4  
          inetアドレス:172.18.21.80 ブロードキャスト:172.18.21.255 マスク:255.255.255.0
          UP BROADCAST MULTICAST  MTU:1500  メトリック:1
          RXパケット:0 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:0 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:0 
          RXバイト:0 (0.0 B)  TXバイト:0 (0.0 B)

eth0      Link encap:イーサネット  ハードウェアアドレス 00:1d:60:6d:ae:b4  
          UP BROADCAST RUNNING MULTICAST  MTU:1500  メトリック:1
          RXパケット:2421136 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:1209165 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:1000 
          RXバイト:583622791 (583.6 MB)  TXバイト:821315537 (821.3 MB)
          割り込み:17 

lo        Link encap:ローカルループバック  
          inetアドレス:127.0.0.1  マスク:255.0.0.0
          inet6アドレス: ::1/128 範囲:ホスト
          UP LOOPBACK RUNNING  MTU:65536  メトリック:1
          RXパケット:7696 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:7696 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:0 
          RXバイト:941701 (941.7 KB)  TXバイト:941701 (941.7 KB)

さて、これでホスタ側の準備は終了です。

Arm64 仮想サーバの起動

qemu-system-aarch64 を実行して、Arm64 仮想サーバをゲストマシンとして起動します。 ブリッジに接続するオプションを付けて qemu-system-aarch64 を起動する場合は管理者権限が必要です。 sudo の後ろで qemu-system-aarch64 を実行します。 長いコマンドラインを何度もキー入力できないので、スクリプトにしておきます。 たとえば start.sh というファイル名で以下のスクリプトを作成します。バックスラッシュ(または円マーク)の直後は改行にしておいて下さい。 「sudo sh start.sh」として実行するとArm64 仮想サーバが起動します。

#!/bin/sh

qemu-system-aarch64 -m 1024 -cpu cortex-a57 -nographic -machine virt \
 -kernel vmlinuz-3.19.0-25-generic \
 -append 'root=/dev/vda1 rw rootwait mem=1024M console=ttyS0 \
  console=ttyAMA0,38400n8 init=/usr/lib/cloud-init/uncloud-init \
  ds=nocloud ubuntu-pass=pass' \
 -drive if=none,id=image,file=vivid-server-cloudimg-arm64-disk1.img \
 -initrd initrd.img-3.19.0-25-generic \
 -device virtio-blk-device,drive=image \
 -device virtio-net-device,netdev=tap0 \
 -netdev tap,id=tap0,script=/etc/qemu-ifup

ホストマシン上、またはssh のコンソール上で上記のスクリプトを実行すると、しばらくゲストOSの起動メッセージが表示された後に、ゲスト(Arm64 仮想マシン)にログインできるようになります。このままArm64 仮想マシンを固定IPに変更してしまいましょう。

Arm64 仮想サーバのネットワーク設定

サーバとしてネットワーク越しにアクセスするので、ゲスト側のArm64仮想マシンのIPアドレスも固定します。 こちらは NetworkManager の管理になっていないため、慣れた古い方法で設定します。ここではIPアドレスを 172.18.21.90 に、ゲートウェイアドレスを172.18.21.1に設定します。


まず、ifconfig コマンドと、 route コマンドで固定のIPを振ってみます。以下のコマンドを実行すると、ネットワーク上の別マシンから ssh で接続できるようになるはずです。

ubuntu@ubuntu:~$ sudo ifconfig eth0 172.18.21.90 netmask 255.255.255.0
ubuntu@ubuntu:~$ sudo route add default gw 172.18.21.1

ubuntu@ubuntu:~$ ifconfig
eth0      Link encap:Ethernet  HWaddr 52:54:00:12:34:56  
          inet addr:172.18.21.90  Bcast:172.18.21.255  Mask:255.255.255.0
          inet6 addr: fe80::5054:ff:fe12:3456/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:263 errors:0 dropped:0 overruns:0 frame:0
          TX packets:31 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:31173 (31.1 KB)  TX bytes:8514 (8.5 KB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:1352 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1352 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:108880 (108.8 KB)  TX bytes:108880 (108.8 KB)

次回から起動時に固定IPになるように /etc/network/interfaces.d/eth0.cfg の内容を修正します。ネームサーバとして 172.18.21.1 を指定しています。

jun@ubuntu:~$ sudo vi /etc/network/interfaces.d/eth0.cfg

私の環境では次のように変更しました。

# The primary network interface
auto eth0
#iface eth0 inet dhcp

iface eth0 inet static
address 172.18.21.90
network i172.18.21.0
netmask 255.255.255.0
broadcast 172.18.21.255
gateway 172.18.21.1
dns-nameservers 172.18.21.1

ssh でリモート接続 (ゲスト)

Arm64 仮想サーバ(ゲスト)を再起動すると固定IPで別マシンから接続できるようになります。

jun-no-MacBook-Pro:~ jun$ ssh -l jun 172.18.21.90
jun@172.18.21.90's password: 
Welcome to Ubuntu 15.04 (GNU/Linux 3.19.0-25-generic aarch64)

 * Documentation:  https://help.ubuntu.com/

  System information as of Thu Aug 13 08:35:57 UTC 2015

  System load:  0.69              Processes:           62
  Usage of /:   51.7% of 2.10GB   Users logged in:     0
  Memory usage: 9%                IP address for eth0: 172.18.21.90
  Swap usage:   0%

  Graph this data and manage this system at:
    https://landscape.canonical.com/

  Get cloud support with Ubuntu Advantage Cloud Guest:
    https://www.ubuntu.com/business/services/cloud


Last login: Wed Aug 12 16:06:00 2015
jun@ubuntu:~$ 

ユーザの追加 (ゲスト)

ここで、ubuntu 以外のユーザを追加しておきましょう。ユーザ名を jun として、sudo が可能な権限を付与します。

ubuntu@ubuntu:~$ sudo adduser jun
sudo: unable to resolve host ubuntu
Adding user `jun' ...
Adding new group `jun' (1001) ...
Adding new user `jun' (1001) with group `jun' ...
Creating home directory `/home/jun' ...
Copying files from `/etc/skel' ...
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully
Changing the user information for jun
Enter the new value, or press ENTER for the default
  Full Name []: 
  Room Number []: 
  Work Phone []: 
  Home Phone []: 
  Other []: 
Is the information correct? [Y/n] y

ubuntu@ubuntu:~$ sudo gpasswd -a jun sudo
Adding user jun to group sudo

samba のインストール (ゲスト)

仮想サーバ内のファイルを外部からやりとりできるように

jun@ubuntu:~$ sudo apt install samba
sudo: unable to resolve host ubuntu
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  attr libaio1 libavahi-client3 libavahi-common-data libavahi-common3 libcups2
  libfile-copy-recursive-perl libhdb9-heimdal libkdc2-heimdal libldb1 libntdb1
  libtalloc2 libtdb1 libtevent0 libwbclient0 python-crypto python-dnspython
  python-ldb python-ntdb python-samba python-talloc python-tdb samba-common
  samba-common-bin samba-dsdb-modules samba-libs samba-vfs-modules tdb-tools
  update-inetd
Suggested packages:
  cups-common python-crypto-dbg python-crypto-doc bind9 bind9utils ldb-tools
  ntp smbldap-tools winbind heimdal-clients
The following NEW packages will be installed:
  attr libaio1 libavahi-client3 libavahi-common-data libavahi-common3 libcups2
  libfile-copy-recursive-perl libhdb9-heimdal libkdc2-heimdal libldb1 libntdb1
  libtalloc2 libtdb1 libtevent0 libwbclient0 python-crypto python-dnspython
  python-ldb python-ntdb python-samba python-talloc python-tdb samba
  samba-common samba-common-bin samba-dsdb-modules samba-libs
  samba-vfs-modules tdb-tools update-inetd
0 upgraded, 30 newly installed, 0 to remove and 0 not upgraded.
Need to get 6,741 kB of archives.
After this operation, 43.5 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
:
略
:

sambaの設定 (ゲスト)

管理者権限でエディタを起動して /etc/samba/smb.conf の193行目付近の[homes]のコメントになっている部分を修正します。

[homes]
   comment = Home Directories
   browseable = yes

# By default, the home directories are exported read-only. Change the
# next parameter to 'no' if you want to be able to write to them.
   read only = no

# File creation mask is set to 0700 for security reasons. If you want to
# create files with group=rw permissions, set next parameter to 0775.
   create mask = 0775

# Directory creation mask is set to 0700 for security reasons. If you want tt
o
# create dirs. with group=rw permissions, set next parameter to 0775.
   directory mask = 0775

# By default, \\server\username shares can be connected to by anyone
# with access to the samba server.
# Un-comment the following parameter to make sure that only "username"
# can connect to \\server\username
# This might need tweaking when using external authentication schemes
   valid users = %S

samba用のユーザ追加 (ゲスト)

$ sudo pdbedit -a -u jun
sudo: unable to resolve host ubuntu
new password:
retype new password:
Unix username:        jun
NT username:          
Account Flags:        [U          ]
User SID:             S-1-5-21-3385742284-1000632516-37778874-1000
Primary Group SID:    S-1-5-21-3385742284-1000632516-37778874-513
Full Name:            
Home Directory:       \\ubuntu\jun
HomeDir Drive:        
Logon Script:         
Profile Path:         \\ubuntu\jun\profile
Domain:               UBUNTU
Account desc:         
Workstations:         
Munged dial:          
Logon time:           0
Logoff time:          Wed, 06 Feb 2036 15:06:39 UTC
Kickoff time:         Wed, 06 Feb 2036 15:06:39 UTC
Password last set:    Wed, 12 Aug 2015 15:40:34 UTC
Password can change:  Wed, 12 Aug 2015 15:40:34 UTC
Password must change: never
Last bad password   : 0
Bad password count  : 0
Logon hours         : FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

設定を反映します。

jun@ubuntu:~$ sudo service samba restart
Failed to restart samba.service: Unit samba.service is masked.

ムムッ、マスクされているってどういうこと?

で、再起動してファイル共有できることを確認しました。

Arm64 のアセンブラを使ってみる (ゲスト)

アセンブラ (GNU as) やリンカ(ld) は binutils に含まれているのでインストールする必要があります。

jun@ubuntu:~$ sudo apt-get install binutils
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Suggested packages:
  binutils-doc
The following NEW packages will be installed:
  binutils
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 2,357 kB of archives.
After this operation, 14.1 MB of additional disk space will be used.
Get:1 https://ports.ubuntu.com/ubuntu-ports/vivid/main binutils arm64 2.25-5ubuntu7 [2,357 kB]
Fetched 2,357 kB in 8s (271 kB/s)                                              
Selecting previously unselected package binutils.
(Reading database ... 57987 files and directories currently installed.)
Preparing to unpack .../binutils_2.25-5ubuntu7_arm64.deb ...
Unpacking binutils (2.25-5ubuntu7) ...
Processing triggers for man-db (2.7.0.2-5) ...
Setting up binutils (2.25-5ubuntu7) ...
Processing triggers for libc-bin (2.21-0ubuntu4) ...

Arm64 のアセンブラで「hello、world」

Arm64 のアセンブラで書いた「hello、world」です。ファイルなどに文字列を出力する Linux のシステムコールである sys_write とプログラムを終了させる sys_exit を使っています。x8 レジスタにシステムコール番号を設定して、「svc #0」命令を実行すると x0 から x5 レジスタの値を引数としてシステムコールと呼ばれる Linux カーネルの各種の機能を使うことができます。メモリ中の位置を示すラベルと呼ぶ _start: と msg: の間の8行がプログラムの実体です。 各命令は4バイトなので文字列データを除けばプログラムは32バイトです。

// Arm64
.text
        .global _start
_start:
        mov     x2,  #13    // x2  length
        adr     x1,  msg    // x1  string address
        mov     x0,  #1     // x0  stdout
        mov     x8,  #64
        svc     #0          // sys_write
        mov     x0,  xzr
        mov     x8,  #93
        svc     #0          // exit
msg:
        .asciz  "hello, world\n"

Arm64 仮想マシンで実行

jun@ubuntu:~$ as -o hello.o hello.s
jun@ubuntu:~$ ld -o hello hello.o
jun@ubuntu:~$ ./hello
hello, world

jun@ubuntu:~$ file hello
hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, not stripped

Dragonboard 410Cで実行

Cortex-A53 という64ビット版のARMを使っている Dragonboard 410C で実行してみましょう。

jun@linaro-alip:~$ as -o hello.o hello.s
jun@linaro-alip:~$ ld -o hello hello.o
jun@linaro-alip:~$ ./hello
hello, world

jun@linaro-alip:~$ file hello
hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, not stripped

当然ですが、Dragonboard 410C でも同じように動作します。

32ビット版のhello, world

比較のためにARMの32ビット版の「hello, world」 です。 短いプログラムですが、色々異なるところがあります。Arm64はコードの字面は32ビット版と似ていますが、内部的な違いが大きいCPUと思います。詳細はまたそのうち。

@ Arm32
.text
        .global _start
_start:
        mov     r2, #13     @ length
        adr     r1, msg     @ address
        mov     r0, #1      @ stdout
        mov     r7, #4      @ sys_write
        swi     0
        mov     r0, #0
        mov     r7, #1      @ sys_exit
        swi     0
msg:
        .asciz  "hello, world\n"

Raspberry Pi2 で実行

ARMの32ビット版のCPU (Cortex-A7) で実行してみます。

jun@raspberrypi ~ $ as -o hello32.o hello32.s
jun@raspberrypi ~ $ ld -o hello32 hello32.o
jun@raspberrypi ~ $ ./hello32
hello, world

Dragonboard 410Cで実行

Dragonboard 410C は Cortex-A53 という64ビット版のARMを使っていますが、32ビット用のプログラムを実行してみましょう。

jun@linaro-alip:~$ ./hello32
hello, world

jun@linaro-alip:~/arm64$ file hello32
hello32: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, not stripped

64ビット版のARM用のLinux では 32ビットLinux用のプログラムも実行できました。

Arm64 仮想マシンで実行

Arm64 仮想マシンでも32ビット用のプログラムを試してみます。

jun@ubuntu:~$ ./hello32
hello, world

jun@ubuntu:~$ file hello32
hello32: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, stripped

問題無いですね。

Dragonboard 410C との互換性?

次の hello2.s というファイル名のコードは、9行目と10行目にx0レジスタをスタックにプッシュして、ポップするコードを追加したものです。

jun@ubuntu:~$ cat hello2.s
.text
        .global _start
_start:
        mov     x2,  #13    // x2  length
        adr     x1,  msg    // x1  string address
        mov     x0,  #1     // x0  stdout
        mov     x8,  #64
        svc     #0          // sys_write
        ldr     x0, [sp, #-8]!  // push x0
        str     x0, [sp], #8    // pop x0
        mov     x0,  xzr
        mov     x8,  #93
        svc     #0          // exit
msg:
        .asciz  "hello, world\n"

jun@ubuntu:~$ as -o hello2.o hello2.s
jun@ubuntu:~$ ld -o hello2 hello2.o
jun@ubuntu:~$ ./hello2
hello, world

仮想Arm64マシン上では普通に実行できます。同じことを Dragonboard 410C で実行します。

jun@linaro-alip:~$ as -o hello2.o hello2.s
jun@linaro-alip:~$ ld -o hello2 hello2.o
jun@linaro-alip:~$ ./hello2
hello, world
Bus error

「Bus error」と表示されて、なにかエラーが起きています。このコードでは「hello, world」を表示したら終了するだけなので分かり難いですが、もっと長いプログラムでは「Bus error」が発生した時点でプログラムは終了します。何が起きているのか調査するためにデバッガ (gdb) で実行してみます。

jun@linaro-alip:~$ gdb ./hello2
:
略
:
(gdb) run
Starting program: /home/jun/arm64/hello2 
hello, world

Program received signal SIGBUS, Bus error.
0x0000000000400090 in _start ()

(gdb) disassemble 
Dump of assembler code for function _start:
   0x0000000000400078 <+0>: mov x2, #0xd                    // #13
   0x000000000040007c <+4>: adr x1, 0x4000a0 <msg>
   0x0000000000400080 <+8>: mov x0, #0x1                    // #1
   0x0000000000400084 <+12>:  mov x8, #0x40                   // #64
   0x0000000000400088 <+16>:  svc #0x0
   0x000000000040008c <+20>:  ldr x0, [sp,#-8]!
=> 0x0000000000400090 <+24>: str  x0, [sp],#8
   0x0000000000400094 <+28>:  mov x0, xzr
   0x0000000000400098 <+32>:  mov x8, #0x5d                   // #93
   0x000000000040009c <+36>:  svc #0x0
End of assembler dump.

スタックポインタが示すメモリに値を書き込む命令で例外が発生しています。スタックポインタの値は16バイトの境界に合わせる必要があるそうです。そこで、次のようにスタックポインタの値を64ビットレジスタ2つ分の16バイトを単位として変化させるとエラーは発生しません。

jun@linaro-alip:~$ cat hello3.s
.text
        .global _start
_start:
        mov     x2,  #13    // x2  length
        adr     x1,  msg    // x1  string address
        mov     x0,  #1     // x0  stdout
        mov     x8,  #64
        svc     #0          // sys_write
        ldr     x0, [sp, #-16]!  // push x0
        str     x0, [sp], #16    // pop x0
        mov     x0,  xzr
        mov     x8,  #93
        svc     #0          // exit
msg:
        .asciz  "hello, world\n"

jun@linaro-alip:~$ as -o hello3.o hello3.s
jun@linaro-alip:~$ ld -o hello3 hello3.o
jun@linaro-alip:~$ ./hello3
hello, world

QEMUも万能ではないようです。Arm64の実機を購入する決心がつきましたか? (笑)

Arm64 のアセンブリプログラミングの詳細はこちら。

続く...



このページの目次