ミドルエンディアン、またはPDPエンディアン

概要

UNIX V1がらみでPDP-11を調べていたら、PDP-11のエンディアンは特殊でミドルエンディアン、またはPDPエンディアンと呼ばれていたことを知った。さっそくテストプログラムをPDP-11シミュレータ上で動かして、その事実を確認してみた。

ミドルエンディアンとは

トルエンディアンとビッグエンディアンの説明は不要だと思うが、最下位バイト(LSB)が低位アドレスにくるのがリトルエンディアンで、最上位バイト(MSB)が低位アドレスにくるのがビックエンディアンである。例えば、UNIXという文字列はリトルエンディアンではXINU*1、ビッグエンディアンではそのままUNIXとメモリ上に格納される。問題のミドルエンディアンでは、UNIXはNUXIと格納される。このことからNUXI問題とも呼ばれている。

なぜこのように格納されてしまうのか? PDP-11はそもそもリトルエンディアンの16ビットマシンであるが、ここで32ビットの値を扱う場合に何が起きるか。コンパイラは値を16ビットごとに分割しリトルエンディアンと逆順に格納してしまうのだ。UNIX文字列の例で説明すると、UNとIXに分割され、それぞれがリトルエンディアンで格納されるので、結果としてNUXIになる。

確認に用いたテストプログラムは次の通りである。比較対象はPDP-11上の2.11BSDとIntel MacBookで試してみた。といっても当然PDP-11の実機なんて持っていないので、シミュレータである。この点の詳細は後述する。

#include <stdio.h>

#ifdef pdp11
typedef unsigned long uint32;
#else
typedef unsigned int uint32;
#endif

int
main()
{
  uint32 i = 0x554e4958; /* 'U''N''I''X' */
  unsigned short *s = (unsigned short *)&i;
  unsigned char *c = (unsigned char *)&i;

#ifdef pdp11
  printf("int:  %X\n", i);
#else
  printf("int:  %x\n", i);
#endif
  printf("short: %x %x\n", s[0], s[1]);
  printf("char:  %x %x %x %x\n", c[0], c[1], c[2], c[3]);

  return 0;
}

結果は次のようになることから、UNIXという文字列がx86ではXINUの順に、PDP-11だとNUXIの順に格納されていることが確認できた。

x86:
int: 554e4958
short: 4958 554e
char: 58 49 4e 55

PDP-11:
int: 554e4958
short: 554e 4958
char: 4e 55 58 49

PDP-11でのcc -S結果のアセンブリも見てみよう(以下は冒頭部分の抜粋)。~からはじまるのはコメントだ。

 1:  .globl  _main
 2:  .text
 3:  _main:
 4:  ~~main:
 5:  jsr     r5,csv
 6:  jbr     L1
 7:  L2:mov  $52516,-14(r5)
 8:  mov     $44530,-12(r5)
 9:  ~i=177764
10:  mov     r5,r0
11:  add     $-14,r0
12:  mov     r0,-16(r5)
13:  ~s=177762
14:  mov     r5,r0
15:  add     $-14,r0
16:  mov     r0,-20(r5)
17:  ~c=177760
18:  mov     -12(r5),-(sp)
19:  mov     -14(r5),-(sp)
20:  mov     $L4,-(sp)
21:  jsr     pc,_printf
22:  add     $6,sp

r5はフレームポインタ(PDP-11用語では環境ポインタ)で、7〜16行目でローカル変数i、s、cを初期化している。ポイントは7、8行目で、052516は0x554e、044530は0x4958のことである。(スタックの図を書けば一発だと思うが)これよりUNに相当する値が低位アドレスに格納されていることが確認できる。

エンディアンと日付の書き方

jargon fileにはエンディアンに関してこんなことが書いてある。日本では日付はYY/MM/DDと書くのでビッグエンディアン、ヨーロッパはDD/MM/YYと書くのでリトルエンディアン、アメリカはMM/DD/YYと書くのでミドルエンディアンだというのだ。なるほど、これは覚えやすいかも。

2.11BSD on SIMH

2.11BSDについては、「V7/x86」で軽く触れたが、PDP-11で動作するBSD UNIXである。この2.11BSD、「UNIX 1st ed.カーネルのソースコード」で紹介したマルチ計算機シミュレータSIMHで、動かすことができる。

ディスクイメージはUNIX Archiveのミラーサイト、例えばhttp://ftp.math.utah.edu:80/pub/mirrors/minnie.tuhs.org/PDP-11/Boot_Images/2.11_on_Simh/からダウンロードできるので、適当なディレクトリに展開して実行する。ちなみに、このカーネルはネットワーク機能も有効になっている。

$ ./pdp11 211bsd.simh

PDP-11 simulator V3.8-1
Listening on port 4000 (socket 4)
Modem control activated
Auto disconnect activated
211bsd.simh> attach xq eth0
File open error
Disabling CR

73Boot from ra(0,0,0) at 0172150
:

ここでリターンキー押下。

: ra(0,0,0)unix
Boot: bootdev=02400 bootcsr=0172150

2.11 BSD UNIX #1: Fri Jun 9 08:42:54 PDT 1995
root@SSU-64EN137:/usr/src/sys/SYSTEM

ra0: Ver 3 mod 3
ra0: RD54 size=311200
attaching qe0 csr 174440
qe0: DEC DELQA addr 08:00:2b:aa:bb:cc
attaching lo0

phys mem = 3145728
avail mem = 1737664
user mem = 307200

June 9 15:33:11 init: configure system

dz 0 csr 160100 vector 300 attached
ra 0 csr 172150 vector 154 vectorset attached
ts 0 csr 172520 vector 224 attached
erase, kill ^U, intr ^C
# ^D

Ctrl-D押下でマルチユーザモードへ。

Fast boot ... skipping disk checks
checking quotas: done.

You need to edit /etc/netstart and /etc/hosts ***


Assuming NETWORKING system ...
add host 2bsd00: gateway localhost
add net default: gateway 192.168.56.1: Network is unreachable
starting system logger
Jun 9 15:33:18 2bsd00 vmunix: ra0: Ver 3 mod 3
Jun 9 15:33:18 2bsd00 vmunix: ra0: RD54 size=311200
checking for core dump...
preserving editor files
clearing /tmp
standard daemons: update cron accounting.
starting network daemons: inetd.
starting local daemons:Fri Jun 9 15:33:18 PDT 1995
Jun 9 15:33:18 2bsd00 June 9 15:33:18 init: kernel security level changed from 0 to 1


2.11 BSD UNIX (2bsd00) (console)

login: root
Password:
erase, kill ^U, intr ^C
# uname -a
2.11BSD 2bsd00 2.11BSD 2.11 BSD UNIX #1: Fri Jun 9 08:42:54 PDT 1995 root@SSU-64EN137:/usr/src/sys/SYSTEM pdp11

2.11BSDの醍醐味はTCP/IPスタックだと思うのだが、これに関してはまた改めて紹介したい。ちなみにSnow leopard上だとネットワーク機能がちゃんと動かせてないので、今はVirtualBoxの中のubuntu 9.04で実験している。。。

それにしても、こんなことをぱっと試せる環境があるってのがすばらしい。

*1:ちなみにXinuという教育用OSがあった。http://en.wikipedia.org/wiki/Xinu また、mtXinuというソフトウェア会社もあったらしい。http://en.wikipedia.org/wiki/MtXinu