気軽に質問できるWebサービス「OSIETE」を作った

Webサービス開発の練習も兼ねて、気軽に質問・回答できるサイトを作った。 Heroku+Django+Bootstrap利用。

近年では検索結果やまとめサイト、ショッピングサイトのサジェストへの依存度が高まっているが、もう少し個人の経験に基づくリコメンド情報も共有されてほしい、と思う。

Amazon EC2のGPUインスタンスでハッシュ解読をやってみる

ハッシュ値から元の文字列を求めるハッシュ解読は、GPUを利用することにより高速に行えることが知られている。 ここでは、Amazon EC2GPUインスタンスを利用し、oclHashcatを使った場合におけるハッシュ解読のパフォーマンスを調べてみる。

環境

US West (Oregon)リージョンの場合、かかる費用は$0.65/hr(1時間70円程度)である。 なお、GPUインスタンスを使うためにはインスタンス上限の制限緩和申請を行っておく必要がある。

oclHashcatでハッシュ解読をやってみる

oclHashcatは、GPUを使ってハッシュ値の解読を試みるアプリケーションである。

まず、EC2サーバにoclHashcatをダウンロードし、展開する。

$ sudo yum-config-manager --enable epel
$ sudo yum install p7zip
$ wget https://hashcat.net/files/cudaHashcat-2.01.7z
$ 7za x cudaHashcat-2.01.7z
$ cd cudaHashcat-2.01/

各種ハッシュ関数の解読速度を調べてみる。

$ ./cudaHashcat64.bin -b
cudaHashcat v2.01 starting in benchmark-mode...

Device #1: GRID K520, 4095MB, 797Mhz, 8MCU

Hashtype: MD4
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:  3700.2 MH/s

Hashtype: MD5
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:  2631.1 MH/s

Hashtype: Half MD5
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   777.2 MH/s

Hashtype: SHA1
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   697.0 MH/s

Hashtype: SHA256
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   286.6 MH/s

Hashtype: SHA384
Workload: 256 loops, 256 accel

Speed.GPU.#1.: 72515.6 kH/s

Hashtype: SHA512
Workload: 256 loops, 256 accel

Speed.GPU.#1.: 72445.1 kH/s

Hashtype: SHA-3(Keccak)
Workload: 128 loops, 256 accel

Speed.GPU.#1.: 56513.4 kH/s

Hashtype: SipHash
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:  3269.6 MH/s

Hashtype: RipeMD160
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   522.4 MH/s

Hashtype: Whirlpool
Workload: 512 loops, 32 accel

Speed.GPU.#1.: 43950.8 kH/s

Hashtype: GOST R 34.11-94
Workload: 512 loops, 64 accel

Speed.GPU.#1.: 41800.3 kH/s

Hashtype: GOST R 34.11-2012 (Streebog) 256-bit
Workload: 512 loops, 16 accel

Speed.GPU.#1.:  9852.4 kH/s

Hashtype: GOST R 34.11-2012 (Streebog) 512-bit
Workload: 512 loops, 16 accel

Speed.GPU.#1.:  9803.3 kH/s

Hashtype: phpass, MD5(Wordpress), MD5(phpBB3), MD5(Joomla)
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:   645.2 kH/s

Hashtype: scrypt
Workload: 1 loops, 64 accel

Speed.GPU.#1.:    25092 H/s

Hashtype: PBKDF2-HMAC-MD5
Workload: 1000 loops, 8 accel

Speed.GPU.#1.:   702.0 kH/s

Hashtype: PBKDF2-HMAC-SHA1
Workload: 1000 loops, 8 accel

Speed.GPU.#1.:   330.0 kH/s

Hashtype: PBKDF2-HMAC-SHA256
Workload: 1000 loops, 8 accel

Speed.GPU.#1.:   114.8 kH/s

Hashtype: PBKDF2-HMAC-SHA512
Workload: 1000 loops, 8 accel

Speed.GPU.#1.:    31925 H/s

Hashtype: Skype
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   779.3 MH/s

Hashtype: WPA/WPA2
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:    41535 H/s

Hashtype: IKE-PSK MD5
Workload: 512 loops, 128 accel

Speed.GPU.#1.:   208.1 MH/s

Hashtype: IKE-PSK SHA1
Workload: 512 loops, 128 accel

Speed.GPU.#1.: 75893.2 kH/s

Hashtype: NetNTLMv1-VANILLA / NetNTLMv1+ESS
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:  1758.0 MH/s

Hashtype: NetNTLMv2
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:   170.0 MH/s

Hashtype: IPMI2 RAKP HMAC-SHA1
Workload: 256 loops, 256 accel

Speed.GPU.#1.:   172.2 MH/s

Hashtype: Kerberos 5 AS-REQ Pre-Auth etype 23
Workload: 256 loops, 32 accel

Speed.GPU.#1.:  6255.5 kH/s

Hashtype: DNSSEC (NSEC3)
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   337.9 MH/s

Hashtype: PostgreSQL Challenge-Response Authentication (MD5)
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   724.9 MH/s

Hashtype: MySQL Challenge-Response Authentication (SHA1)
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   239.4 MH/s

Hashtype: SIP digest authentication (MD5)
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:   443.2 MH/s

Hashtype: SMF > v1.1
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   275.1 MH/s

Hashtype: vBulletin < v3.8.5
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   713.8 MH/s

Hashtype: vBulletin > v3.8.5
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   515.0 MH/s

Hashtype: IPB2+, MyBB1.2+
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   526.3 MH/s

Hashtype: WBB3, Woltlab Burning Board 3
Workload: 256 loops, 256 accel

Speed.GPU.#1.:   137.4 MH/s

Hashtype: Joomla < 2.5.18
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:  2631.4 MH/s

Hashtype: PHPS
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   714.1 MH/s

Hashtype: Drupal7
Workload: 1024 loops, 8 accel

Speed.GPU.#1.:     4302 H/s

Hashtype: osCommerce, xt:Commerce
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   779.3 MH/s

Hashtype: PrestaShop
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   937.8 MH/s

Hashtype: Django (SHA-1)
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   273.1 MH/s

Hashtype: Django (PBKDF2-SHA256)
Workload: 1024 loops, 8 accel

Speed.GPU.#1.:     5806 H/s

Hashtype: Mediawiki B type
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   554.3 MH/s

Hashtype: Redmine Project Management Web App
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   231.6 MH/s

Hashtype: PostgreSQL
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:  2632.8 MH/s

Hashtype: MSSQL(2000)
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   668.8 MH/s

Hashtype: MSSQL(2005)
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   668.6 MH/s

Hashtype: MSSQL(2012)
Workload: 256 loops, 256 accel

Speed.GPU.#1.: 72135.6 kH/s

Hashtype: MySQL323
Workload: 512 loops, 256 accel

Speed.GPU.#1.:  8965.3 MH/s

Hashtype: MySQL4.1/MySQL5
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   338.3 MH/s

Hashtype: Oracle H: Type (Oracle 7+)
Workload: 512 loops, 64 accel

Speed.GPU.#1.:   115.2 MH/s

Hashtype: Oracle S: Type (Oracle 11+)
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   696.8 MH/s

Hashtype: Oracle T: Type (Oracle 12+)
Workload: 1024 loops, 8 accel

Speed.GPU.#1.:     7812 H/s

Hashtype: Sybase ASE
Workload: 512 loops, 32 accel

Speed.GPU.#1.: 34292.9 kH/s

Hashtype: EPiServer 6.x < v4
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   273.0 MH/s

Hashtype: EPiServer 6.x > v4
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   268.2 MH/s

Hashtype: md5apr1, MD5(APR), Apache MD5
Workload: 1000 loops, 32 accel

Speed.GPU.#1.:  1173.5 kH/s

Hashtype: ColdFusion 10+
Workload: 128 loops, 128 accel

Speed.GPU.#1.:   188.8 MH/s

Hashtype: hMailServer
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   268.2 MH/s

Hashtype: SHA-1(Base64), nsldap, Netscape LDAP SHA
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   697.1 MH/s

Hashtype: SSHA-1(Base64), nsldaps, Netscape LDAP SSHA
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   696.7 MH/s

Hashtype: SSHA-512(Base64), LDAP {SSHA512}
Workload: 256 loops, 256 accel

Speed.GPU.#1.: 72501.6 kH/s

Hashtype: LM
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   483.0 MH/s

Hashtype: NTLM
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:  3616.9 MH/s

Hashtype: Domain Cached Credentials (DCC), MS Cache
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:  1204.0 MH/s

Hashtype: Domain Cached Credentials 2 (DCC2), MS Cache 2
Workload: 1024 loops, 16 accel

Speed.GPU.#1.:    33952 H/s

Hashtype: MS-AzureSync PBKDF2-HMAC-SHA256
Workload: 100 loops, 256 accel

Speed.GPU.#1.:  1202.3 kH/s

Hashtype: descrypt, DES(Unix), Traditional DES
Workload: 1024 loops, 64 accel

Speed.GPU.#1.: 17319.2 kH/s

Hashtype: BSDiCrypt, Extended DES
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   223.8 kH/s

Hashtype: md5crypt, MD5(Unix), FreeBSD MD5, Cisco-IOS MD5
Workload: 1000 loops, 32 accel

Speed.GPU.#1.:  1188.1 kH/s

Hashtype: bcrypt, Blowfish(OpenBSD)
Workload: 32 loops, 2 accel

Speed.GPU.#1.:      509 H/s

Hashtype: sha256crypt, SHA256(Unix)
Workload: 1024 loops, 4 accel

Speed.GPU.#1.:    44242 H/s

Hashtype: sha512crypt, SHA512(Unix)
Workload: 1024 loops, 8 accel

Speed.GPU.#1.:    12919 H/s

Hashtype: OSX v10.4, v10.5, v10.6
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   274.7 MH/s

Hashtype: OSX v10.7
Workload: 128 loops, 256 accel

Speed.GPU.#1.: 70910.0 kH/s

Hashtype: OSX v10.8+
Workload: 1024 loops, 2 accel

Speed.GPU.#1.:      824 H/s

Hashtype: AIX {smd5}
Workload: 1000 loops, 32 accel

Speed.GPU.#1.:  1173.1 kH/s

Hashtype: AIX {ssha1}
Workload: 64 loops, 128 accel

Speed.GPU.#1.:  4397.9 kH/s

Hashtype: AIX {ssha256}
Workload: 64 loops, 128 accel

Speed.GPU.#1.:  1781.6 kH/s

Hashtype: AIX {ssha512}
Workload: 64 loops, 32 accel

Speed.GPU.#1.:   483.2 kH/s

Hashtype: Cisco-PIX MD5
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:  1792.4 MH/s

Hashtype: Cisco-ASA MD5
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:  1876.0 MH/s

Hashtype: Cisco-IOS SHA256
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   286.5 MH/s

Hashtype: Cisco $8$
Workload: 1024 loops, 8 accel

Speed.GPU.#1.:     5807 H/s

Hashtype: Cisco $9$
Workload: 1 loops, 4 accel

Speed.GPU.#1.:      966 H/s

Hashtype: Juniper Netscreen/SSG (ScreenOS)
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   779.6 MH/s

Hashtype: Juniper IVE
Workload: 1000 loops, 32 accel

Speed.GPU.#1.:  1188.3 kH/s

Hashtype: Android PIN
Workload: 1024 loops, 16 accel

Speed.GPU.#1.:   615.1 kH/s

Hashtype: Citrix NetScaler
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   754.8 MH/s

Hashtype: RACF
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   260.5 MH/s

Hashtype: GRUB 2
Workload: 1024 loops, 2 accel

Speed.GPU.#1.:     2884 H/s

Hashtype: Radmin2
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   859.6 MH/s

Hashtype: SAP CODVN B (BCODE)
Workload: 1024 loops, 64 accel

Speed.GPU.#1.:   219.6 MH/s

Hashtype: SAP CODVN F/G (PASSCODE)
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:   107.3 MH/s

Hashtype: SAP CODVN H (PWDSALTEDHASH) iSSHA-1
Workload: 1024 loops, 16 accel

Speed.GPU.#1.:   594.8 kH/s

Hashtype: Lotus Notes/Domino 5
Workload: 256 loops, 32 accel

Speed.GPU.#1.: 28342.8 kH/s

Hashtype: Lotus Notes/Domino 6
Workload: 256 loops, 32 accel

Speed.GPU.#1.:  9226.5 kH/s

Hashtype: Lotus Notes/Domino 8
Workload: 1024 loops, 64 accel

Speed.GPU.#1.:    72211 H/s

Hashtype: PeopleSoft
Workload: 512 loops, 256 accel

Speed.GPU.#1.:   668.5 MH/s

Hashtype: 7-Zip
Workload: 1024 loops, 4 accel

Speed.GPU.#1.:     1040 H/s

Hashtype: RAR3-hp
Workload: 16384 loops, 32 accel

Speed.GPU.#1.:     7062 H/s

Hashtype: TrueCrypt 5.0+ PBKDF2-HMAC-RipeMD160 + XTS 512 bit
Workload: 1024 loops, 64 accel

Speed.GPU.#1.:    31093 H/s

Hashtype: TrueCrypt 5.0+ PBKDF2-HMAC-SHA512 + XTS 512 bit
Workload: 1000 loops, 8 accel

Speed.GPU.#1.:    30514 H/s

Hashtype: TrueCrypt 5.0+ PBKDF2-HMAC-Whirlpool + XTS 512 bit
Workload: 1000 loops, 8 accel

Speed.GPU.#1.:     6080 H/s

Hashtype: TrueCrypt 5.0+ PBKDF2-HMAC-RipeMD160 + XTS 512 bit + boot-mode
Workload: 1000 loops, 128 accel

Speed.GPU.#1.:    59915 H/s

Hashtype: Android FDE <= 4.3
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:    84545 H/s

Hashtype: eCryptfs
Workload: 1024 loops, 8 accel

Speed.GPU.#1.:     1068 H/s

Hashtype: MS Office <= 2003 MD5 + RC4, oldoffice$0, oldoffice$1
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:  6063.9 kH/s

Hashtype: MS Office <= 2003 MD5 + RC4, collision-mode #1
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:  9726.9 kH/s

Hashtype: MS Office <= 2003 SHA1 + RC4, oldoffice$3, oldoffice$4
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:  8639.1 kH/s

Hashtype: MS Office <= 2003 SHA1 + RC4, collision-mode #1
Workload: 1024 loops, 32 accel

Speed.GPU.#1.: 10105.9 kH/s

Hashtype: Office 2007
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:    14160 H/s

Hashtype: Office 2010
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:     7087 H/s

Hashtype: Office 2013
Workload: 1024 loops, 4 accel

Speed.GPU.#1.:      699 H/s

Hashtype: PDF 1.1 - 1.3 (Acrobat 2 - 4)
Workload: 1024 loops, 32 accel

Speed.GPU.#1.:  9990.0 kH/s

Hashtype: PDF 1.1 - 1.3 (Acrobat 2 - 4) + collider-mode #1
Workload: 1024 loops, 32 accel

Speed.GPU.#1.: 11320.5 kH/s

Hashtype: PDF 1.4 - 1.6 (Acrobat 5 - 8)
Workload: 70 loops, 256 accel

Speed.GPU.#1.:   469.1 kH/s

Hashtype: PDF 1.7 Level 3 (Acrobat 9)
Workload: 1024 loops, 256 accel

Speed.GPU.#1.:   286.5 MH/s

Hashtype: PDF 1.7 Level 8 (Acrobat 10 - 11)
Workload: 64 loops, 8 accel

Speed.GPU.#1.:     3984 H/s

Hashtype: Password Safe v2
Workload: 1000 loops, 16 accel

Speed.GPU.#1.:    10654 H/s

Hashtype: Password Safe v3
Workload: 1024 loops, 16 accel

Speed.GPU.#1.:   118.4 kH/s

Hashtype: Lastpass
Workload: 500 loops, 64 accel

Speed.GPU.#1.:   249.4 kH/s

Hashtype: 1Password, agilekeychain
Workload: 1000 loops, 64 accel

Speed.GPU.#1.:   357.1 kH/s

Hashtype: 1Password, cloudkeychain
Workload: 1024 loops, 2 accel

Speed.GPU.#1.:      722 H/s

Hashtype: Bitcoin/Litecoin wallet.dat
Workload: 1024 loops, 2 accel

Speed.GPU.#1.:      323 H/s

Hashtype: Blockchain, My Wallet
Workload: 10 loops, 256 accel

Speed.GPU.#1.:  6941.5 kH/s

Started: Thu May 19 13:06:59 2016
Stopped: Thu May 19 13:47:20 2016

上の結果から、単純なハッシュ関数であるMD5SHA-1、SHA-256に比べ、鍵導出関数と呼ばれるPBKDF2やscrypt、bcryptの解読速度が著しく遅いことが確認できる。 また、Core i5のサーバで計測した下の結果と比べると、解読速度に100倍程度の違いがあることがわかる。

$ ./hashcat-cli64.bin -b
Initializing hashcat v2.00 with 4 threads and 32mb segment-size...

Device...........: Intel(R) Core(TM) i5-4200U CPU @ 1.60GHz
Instruction set..: x86_64
Number of threads: 4

Hash type: MD4
Speed/sec: 33.06M words

Hash type: MD5
Speed/sec: 28.22M words

Hash type: SHA1
Speed/sec: 15.90M words

Hash type: SHA256
Speed/sec: 8.01M words

Hash type: SHA512
Speed/sec: 3.30M words

Hash type: SHA-3(Keccak)
Speed/sec: 3.38M words

(snip)

試しに、passwordという8文字の文字列のMD5ハッシュ値を用意する。

$ echo -n password | md5sum
5f4dcc3b5aa765d61d8327deb882cf99  -
$ echo 5f4dcc3b5aa765d61d8327deb882cf99 >hash.txt

mask_attack [hashcat wiki]を参考に、英小文字と数字からなる8文字以下のMD5ハッシュ値についてブルートフォースを行うと次のようになる。

$ ./cudaHashcat64.bin -m 0 -a 3 -i hash.txt -1 ?l?d ?1?1?1?1?1?1?1?1
cudaHashcat v2.01 starting...

Device #1: GRID K520, 4095MB, 797Mhz, 8MCU

Hashes: 1 hashes; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Applicable Optimizers:
* Zero-Byte
* Precompute-Init
* Precompute-Merkle-Demgard
* Meet-In-The-Middle
* Early-Skip
* Not-Salted
* Not-Iterated
* Single-Hash
* Single-Salt
* Brute-Force
* Scalar-Mode
* Raw-Hash
Watchdog: Temperature abort trigger set to 90c
Watchdog: Temperature retain trigger set to 80c
Device #1: Kernel ./kernels/4318/m00000_a3.sm_30.64.cubin
Device #1: Kernel ./kernels/4318/markov_le_v1.sm_30.64.cubin


ATTENTION!
  The wordlist or mask you are using is too small.
  Therefore, oclHashcat is unable to utilize the full parallelization power of your GPU(s).
  The cracking speed will drop.
  Workaround: https://hashcat.net/wiki/doku.php?id=frequently_asked_questions#how_to_create_more_work_for_full_speed


INFO: approaching final keyspace, workload adjusted


Session.Name...: cudaHashcat
Status.........: Running
Input.Mode.....: Mask (?1) [1]
Hash.Target....: 5f4dcc3b5aa765d61d8327deb882cf99
Hash.Type......: MD5
Time.Started...: 0 secs
Time.Estimated.: 0 secs
Speed.GPU.#1...:        0 H/s
Recovered......: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.......: 36/36 (100.00%)
Rejected.......: 0/36 (0.00%)
HWMon.GPU.#1...:  1% Util, 35c Temp, N/A Fan


ATTENTION!
  The wordlist or mask you are using is too small.
  Therefore, oclHashcat is unable to utilize the full parallelization power of your GPU(s).
  The cracking speed will drop.
  Workaround: https://hashcat.net/wiki/doku.php?id=frequently_asked_questions#how_to_create_more_work_for_full_speed


INFO: approaching final keyspace, workload adjusted


Session.Name...: cudaHashcat
Status.........: Running
Input.Mode.....: Mask (?1?1) [2]
Hash.Target....: 5f4dcc3b5aa765d61d8327deb882cf99
Hash.Type......: MD5
Time.Started...: 0 secs
Time.Estimated.: 0 secs
Speed.GPU.#1...:     4977 H/s
Recovered......: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.......: 1296/1296 (100.00%)
Rejected.......: 0/1296 (0.00%)
HWMon.GPU.#1...:  0% Util, 35c Temp, N/A Fan


ATTENTION!
  The wordlist or mask you are using is too small.
  Therefore, oclHashcat is unable to utilize the full parallelization power of your GPU(s).
  The cracking speed will drop.
  Workaround: https://hashcat.net/wiki/doku.php?id=frequently_asked_questions#how_to_create_more_work_for_full_speed


INFO: approaching final keyspace, workload adjusted


Session.Name...: cudaHashcat
Status.........: Running
Input.Mode.....: Mask (?1?1?1) [3]
Hash.Target....: 5f4dcc3b5aa765d61d8327deb882cf99
Hash.Type......: MD5
Time.Started...: 0 secs
Time.Estimated.: 0 secs
Speed.GPU.#1...:   170.7 kH/s
Recovered......: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.......: 46656/46656 (100.00%)
Rejected.......: 0/46656 (0.00%)
HWMon.GPU.#1...:  0% Util, 35c Temp, N/A Fan


ATTENTION!
  The wordlist or mask you are using is too small.
  Therefore, oclHashcat is unable to utilize the full parallelization power of your GPU(s).
  The cracking speed will drop.
  Workaround: https://hashcat.net/wiki/doku.php?id=frequently_asked_questions#how_to_create_more_work_for_full_speed


INFO: approaching final keyspace, workload adjusted


Session.Name...: cudaHashcat
Status.........: Running
Input.Mode.....: Mask (?1?1?1?1) [4]
Hash.Target....: 5f4dcc3b5aa765d61d8327deb882cf99
Hash.Type......: MD5
Time.Started...: 0 secs
Time.Estimated.: 0 secs
Speed.GPU.#1...:  6313.7 kH/s
Recovered......: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.......: 1679616/1679616 (100.00%)
Rejected.......: 0/1679616 (0.00%)
HWMon.GPU.#1...:  1% Util, 35c Temp, N/A Fan


INFO: approaching final keyspace, workload adjusted


Session.Name...: cudaHashcat
Status.........: Running
Input.Mode.....: Mask (?1?1?1?1?1) [5]
Hash.Target....: 5f4dcc3b5aa765d61d8327deb882cf99
Hash.Type......: MD5
Time.Started...: 0 secs
Time.Estimated.: 0 secs
Speed.GPU.#1...:   188.1 MH/s
Recovered......: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.......: 60466176/60466176 (100.00%)
Rejected.......: 0/60466176 (0.00%)
HWMon.GPU.#1...:  0% Util, 37c Temp, N/A Fan


INFO: approaching final keyspace, workload adjusted


Session.Name...: cudaHashcat
Status.........: Running
Input.Mode.....: Mask (?1?1?1?1?1?1) [6]
Hash.Target....: 5f4dcc3b5aa765d61d8327deb882cf99
Hash.Type......: MD5
Time.Started...: 0 secs
Time.Estimated.: 0 secs
Speed.GPU.#1...:  1916.5 MH/s
Recovered......: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.......: 2176782336/2176782336 (100.00%)
Rejected.......: 0/2176782336 (0.00%)
HWMon.GPU.#1...: 99% Util, 40c Temp, N/A Fan


INFO: approaching final keyspace, workload adjusted


Session.Name...: cudaHashcat
Status.........: Running
Input.Mode.....: Mask (?1?1?1?1?1?1?1) [7]
Hash.Target....: 5f4dcc3b5aa765d61d8327deb882cf99
Hash.Type......: MD5
Time.Started...: Thu May 19 14:17:10 2016 (30 secs)
Time.Estimated.: 0 secs
Speed.GPU.#1...:  2555.6 MH/s
Recovered......: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.......: 78364164096/78364164096 (100.00%)
Rejected.......: 0/78364164096 (0.00%)
HWMon.GPU.#1...: 99% Util, 49c Temp, N/A Fan

5f4dcc3b5aa765d61d8327deb882cf99:password

Session.Name...: cudaHashcat
Status.........: Cracked
Input.Mode.....: Mask (?1?1?1?1?1?1?1?1) [8]
Hash.Target....: 5f4dcc3b5aa765d61d8327deb882cf99
Hash.Type......: MD5
Time.Started...: Thu May 19 14:17:10 2016 (1 min, 58 secs)
Speed.GPU.#1...:  2593.9 MH/s
Recovered......: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.......: 306570067968/2821109907456 (10.87%)
Rejected.......: 0/306570067968 (0.00%)
Restore.Point..: 6553600/60466176 (10.84%)
HWMon.GPU.#1...:  0% Util, 57c Temp, N/A Fan

Started: Thu May 19 14:17:10 2016
Stopped: Thu May 19 14:19:43 2016

上の結果より、2分30秒程度でハッシュ解読に成功していることが確認できる。

ここで、英小文字、英大文字、数字、記号(?a、94文字)で8文字以下のMD5ブルートフォースにかかる時間を推定すると、27日程度となる。

(94 + 94^2 + ... + 94^8) / (2631.1 * 1000000)
= 94 * (1-94^8)/(1-94) / 2631100000
= 2341695.272914663 (secs)
= 27.102954547623415 (days)

また、GPUが四つのg2.8xlargeインスタンスを使った場合、かかる時間は上記の4分の1程度となることが推定できる。

関連リンク

Pythonでネイティブコードを実行する

Pythonでネイティブコード(x86バイトコードなど)を実行する方法のメモ。

ctypesモジュールをインポートし、次のような関数を定義すればよい。

import ctypes

def native_func(bytecode):
    libc = ctypes.CDLL('libc.so.6')
    libc.mmap.restype = ctypes.c_void_p
    buf = libc.mmap(None, len(bytecode), 7, 0x22, -1, 0)
    libc.memcpy(ctypes.c_void_p(buf), ctypes.c_char_p(bytecode), len(bytecode))
    return ctypes.CFUNCTYPE(ctypes.c_void_p)(buf)

rdrand = native_func('\x48\x0f\xc7\xf0\xc3')  # rdrand rax; ret
print hex(rdrand())

上のコードでは、例としてハードウェア乱数を生成するRDRAND命令を実行し、その結果を返す関数を定義している。

実際に実行すると、実行ごとにランダムな値が返っていることが確認できる。

$ python native_func.py
0xd8e5dd17b96e3b07L

$ python native_func.py
0xdfbac12088c27055L

追記(2016-06-06)

上ではネイティブコードの例としてRDRAND命令を実行したが、単にセキュアな乱数が必要な場合はos.urandom()を用いればよい。

# urandom.py
import os
import struct

randvalue = struct.unpack('<Q', os.urandom(8))[0]
print hex(randvalue)
$ python urandom.py
0xd67b1aeabffab050L

$ python urandom.py
0x784919deb3fa692

さらに安全性を求める場合は/dev/randomを利用することになるが、このデバイスは十分なエントロピーが確保されるまでブロックされることに注意する必要がある。

関連リンク

区間ふるいで2^32未満の素数を列挙する

232未満の素数すべてを列挙するアルゴリズムについてのメモ。 ついでに、C++11、Go、Rustの比較もやってみる。

環境

Ubuntu 14.04.4 LTS 64bit版、g++ 4.8.4、Go 1.6.2、Rust 1.8.0

$ uname -a
Linux vm-ubuntu64 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.4 LTS
Release:        14.04
Codename:       trusty

$ g++ --version
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4

$ go version
go version go1.6.2 linux/amd64

$ rustc --version
rustc 1.8.0 (db2939409 2016-04-11)

区間ふるいによる素数列挙

単に232未満の最大の素数を求めるだけであれば、232から逆順に試し割りなどの素数判定アルゴリズムを適用すればよい。 一方、232未満のすべての素数を求める場合、素数列挙アルゴリズムを用いる必要がある。

素数列挙アルゴリズムの代表的なものにエラトステネスのふるいがあるが、単純な方法では最初に求めたい区間のテーブルを確保する必要があるため、232のような大きな区間については適用が難しい。 このような場合は、区間ふるい(Segmented Sieve)を用いることにより効率的に素数を列挙することができる。

区間ふるいは次のようなアルゴリズムである。

  1. 求めたい区間[M, N]の最大値Nに対し、sqrt(N)以下の素数Psをエラトステネスのふるいで列挙する
  2. [M, N]の区間についてテーブルを確保し、Psの倍数となる数をふるいにかける
    • [M, N]の区間が大きい場合は、適度な大きさに分割してそれぞれふるいにかければよい

232の区間を216ごとに分割する例について、C++11でコードで書くと次のようになる。

// sieve.cpp
#include <iostream>
#include <cstdint>
#include <bitset>
#include <vector>
using namespace std;

int main()
{
    bitset<1<<16> is_composite;
    vector<uint32_t> primes;
    uint32_t i, j, k;

    for (i=2; i<1<<8; i++) {
        if (is_composite[i]) {
            continue;
        }

        for (j=i*2; j<1<<16; j+=i) {
            is_composite[j] = 1;
        }
    }

    for (i=2; i<1<<16; i++) {
        if (!is_composite[i]) {
            cout << i << endl;
            primes.push_back(i);
        }
    }

    for (k=1; k<1<<16; k++) {
        is_composite.reset();
        uint32_t offset = k * (1<<16);

        for (auto p : primes) {
            i = offset + (p - offset % p) % p;
            while (i - offset < 1<<16) {
                is_composite[i - offset] = 1;
                i += p;
            }
        }

        for (i=0; i<1<<16; i++) {
            if (!is_composite[i]) {
                cout << offset + i << endl;
            }
        }
    }

    return 0;
}

比較の目的も兼ねて、GoおよびRustで同様のコードを書くと次のようになる。

// sieve.go
package main

import "fmt"

func main() {
    var is_composite [1<<16]bool
    primes := []uint32{}

    for i := 2; i < 1<<8; i++ {
        if is_composite[i] {
            continue;
        }

        for j := i*2; j < 1<<16; j += i {
            is_composite[j] = true;
        }
    }

    for i := uint32(2); i < 1<<16; i++ {
        if !is_composite[i] {
            fmt.Println(i)
            primes = append(primes, i)
        }
    }

    for k := 1; k < 1<<16; k++ {
        for i := range is_composite {
            is_composite[i] = false
        }
        offset := uint32(k * (1<<16))

        for _, p := range primes {
            j := offset + (p - offset % p) % p
            for j - offset < 1<<16 {
                is_composite[j - offset] = true
                j += p
            }
        }

        for i := uint32(0); i < 1<<16; i++ {
            if !is_composite[i] {
                fmt.Println(offset + i)
            }
        }
    }
}
// sieve.rs
fn main() {
    let mut is_composite = [false; 1<<16];
    let mut primes = vec![];

    for i in 2..1<<8 {
        if is_composite[i] {
            continue;
        }

        let mut j = i*2;
        while j < 1<<16 {
            is_composite[j] = true;
            j += i;
        }
    }

    for i in 2..1<<16 {
        if !is_composite[i] {
            println!("{}", i);
            primes.push(i);
        }
    }

    for k in 1..1<<16 {
        is_composite = [false; 1<<16];
        let offset = k * (1<<16);

        for &p in primes.iter() {
            let mut i = offset + (p - offset % p) % p;
            while i - offset < 1<<16 {
                is_composite[i - offset] = true;
                i += p;
            }
        }

        for i in 0..1<<16 {
            if !is_composite[i] {
                println!("{}", offset + i);
            }
        }
    }
}

コンパイルにかかる時間を調べてみる。

$ time g++ -O2 -std=c++11 sieve.cpp -o sieve_cpp

real    0m0.341s
user    0m0.316s
sys     0m0.020s

$ time go build -o sieve_go sieve.go

real    0m0.434s
user    0m0.552s
sys     0m0.088s

$ time rustc -O sieve.rs -o sieve_rs

real    0m0.405s
user    0m0.372s
sys     0m0.032s

コンパイル時間には大きな差がないことがわかる。

次に、実行にかかる時間を調べてみる。

$ time ./sieve_cpp >sieve_cpp.log

real    6m10.568s
user    1m29.476s
sys     4m18.960s

$ time ./sieve_go >sieve_go.log

real    7m4.716s
user    2m19.144s
sys     4m33.612s

$ time ./sieve_rs >sieve_rs.log

real    6m21.845s
user    1m44.284s
sys     4m14.080s

ここではディスクI/O含むカーネル処理の時間(sys)は重要でないため、userに注目する。 C++とRustには大きな差がないが、Goは1分ほど長く時間がかかっていることがわかる。

生成される実行ファイルのサイズを調べてみる。

$ ls -l sieve_*
-rwxr-xr-x 1 user user      13812 May  6 07:48 sieve_cpp*
-rw-r--r-- 1 user user 2178719347 May  6 07:30 sieve_cpp.log
-rwxr-xr-x 1 user user    2292936 May  6 07:48 sieve_go*
-rw-r--r-- 1 user user 2178719347 May  6 07:38 sieve_go.log
-rwxr-xr-x 1 user user     586264 May  6 07:49 sieve_rs*
-rw-r--r-- 1 user user 2178719347 May  6 07:47 sieve_rs.log

ランタイムライブラリを含まないC++が最も小さく、Rust、Goと続くことがわかる。 また、同一の出力結果が得られていることも確認できる。

出力結果の内容を確認してみる。

$ tail sieve_cpp.log
4294967029
4294967087
4294967111
4294967143
4294967161
4294967189
4294967197
4294967231
4294967279
4294967291

$ factor 4294967291
4294967291: 4294967291

$ python -c "print 1<<32"
4294967296

上の結果から、232未満の最大の素数が4294967291であることが確認できる。

参考:生成されるアセンブリコード

ここでは、main関数に相当する部分のみを抜き出す。

$ objdump -d sieve_cpp | c++filt | awk '/<main/,/^$/'
00000000004009e0 <main>:
  4009e0:       41 57                   push   r15
  4009e2:       b9 00 04 00 00          mov    ecx,0x400
  4009e7:       31 c0                   xor    eax,eax
  4009e9:       41 b8 03 00 00 00       mov    r8d,0x3
  4009ef:       be 02 00 00 00          mov    esi,0x2
  4009f4:       41 56                   push   r14
  4009f6:       41 55                   push   r13
  4009f8:       41 54                   push   r12
  4009fa:       55                      push   rbp
  4009fb:       53                      push   rbx
  4009fc:       48 81 ec 38 20 00 00    sub    rsp,0x2038
  400a03:       48 8d 6c 24 30          lea    rbp,[rsp+0x30]
  400a08:       48 c7 44 24 10 00 00    mov    QWORD PTR [rsp+0x10],0x0
  400a0f:       00 00
  400a11:       48 c7 44 24 18 00 00    mov    QWORD PTR [rsp+0x18],0x0
  400a18:       00 00
  400a1a:       48 c7 44 24 20 00 00    mov    QWORD PTR [rsp+0x20],0x0
  400a21:       00 00
  400a23:       c7 44 24 0c 02 00 00    mov    DWORD PTR [rsp+0xc],0x2
  400a2a:       00
  400a2b:       48 89 ef                mov    rdi,rbp
  400a2e:       f3 48 ab                rep stos QWORD PTR es:[rdi],rax
  400a31:       bf 01 00 00 00          mov    edi,0x1
  400a36:       48 89 fa                mov    rdx,rdi
  400a39:       89 f1                   mov    ecx,esi
  400a3b:       48 d3 e2                shl    rdx,cl
  400a3e:       48 85 c2                test   rdx,rax
  400a41:       75 1e                   jne    400a61 <main+0x81>
  400a43:       8d 0c 36                lea    ecx,[rsi+rsi*1]
  400a46:       89 c8                   mov    eax,ecx
  400a48:       48 89 fa                mov    rdx,rdi
  400a4b:       48 d3 e2                shl    rdx,cl
  400a4e:       48 c1 e8 06             shr    rax,0x6
  400a52:       01 f1                   add    ecx,esi
  400a54:       48 09 54 c4 30          or     QWORD PTR [rsp+rax*8+0x30],rdx
  400a59:       81 f9 ff ff 00 00       cmp    ecx,0xffff
  400a5f:       76 e5                   jbe    400a46 <main+0x66>
  400a61:       83 c6 01                add    esi,0x1
  400a64:       81 fe 00 01 00 00       cmp    esi,0x100
  400a6a:       89 74 24 0c             mov    DWORD PTR [rsp+0xc],esi
  400a6e:       74 12                   je     400a82 <main+0xa2>
  400a70:       4c 89 c0                mov    rax,r8
  400a73:       49 83 c0 01             add    r8,0x1
  400a77:       48 c1 e8 06             shr    rax,0x6
  400a7b:       48 8b 44 c4 30          mov    rax,QWORD PTR [rsp+rax*8+0x30]
  400a80:       eb b4                   jmp    400a36 <main+0x56>
  400a82:       c7 44 24 0c 02 00 00    mov    DWORD PTR [rsp+0xc],0x2
  400a89:       00
  400a8a:       b9 02 00 00 00          mov    ecx,0x2
  400a8f:       bb 01 00 00 00          mov    ebx,0x1
  400a94:       eb 17                   jmp    400aad <main+0xcd>
  400a96:       8b 4c 24 0c             mov    ecx,DWORD PTR [rsp+0xc]
  400a9a:       83 c1 01                add    ecx,0x1
  400a9d:       81 f9 ff ff 00 00       cmp    ecx,0xffff
  400aa3:       89 4c 24 0c             mov    DWORD PTR [rsp+0xc],ecx
  400aa7:       0f 87 9b 00 00 00       ja     400b48 <main+0x168>
  400aad:       89 ce                   mov    esi,ecx
  400aaf:       48 89 da                mov    rdx,rbx
  400ab2:       48 89 f0                mov    rax,rsi
  400ab5:       48 d3 e2                shl    rdx,cl
  400ab8:       48 c1 e8 06             shr    rax,0x6
  400abc:       48 85 54 c4 30          test   QWORD PTR [rsp+rax*8+0x30],rdx
  400ac1:       75 d3                   jne    400a96 <main+0xb6>
  400ac3:       bf a0 20 60 00          mov    edi,0x6020a0
  400ac8:       e8 c3 fe ff ff          call   400990 <std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<unsigned long>(unsigned long)@plt>
  400acd:       49 89 c5                mov    r13,rax
  400ad0:       48 8b 00                mov    rax,QWORD PTR [rax]
  400ad3:       48 8b 40 e8             mov    rax,QWORD PTR [rax-0x18]
  400ad7:       4d 8b a4 05 f0 00 00    mov    r12,QWORD PTR [r13+rax*1+0xf0]
  400ade:       00
  400adf:       4d 85 e4                test   r12,r12
  400ae2:       0f 84 13 02 00 00       je     400cfb <main+0x31b>
  400ae8:       41 80 7c 24 38 00       cmp    BYTE PTR [r12+0x38],0x0
  400aee:       0f 84 72 01 00 00       je     400c66 <main+0x286>
  400af4:       41 0f b6 44 24 43       movzx  eax,BYTE PTR [r12+0x43]
  400afa:       0f be f0                movsx  esi,al
  400afd:       4c 89 ef                mov    rdi,r13
  400b00:       e8 cb fe ff ff          call   4009d0 <std::basic_ostream<char, std::char_traits<char> >::put(char)@plt>
  400b05:       48 89 c7                mov    rdi,rax
  400b08:       e8 73 fe ff ff          call   400980 <std::basic_ostream<char, std::char_traits<char> >::flush()@plt>
  400b0d:       48 8b 44 24 18          mov    rax,QWORD PTR [rsp+0x18]
  400b12:       48 3b 44 24 20          cmp    rax,QWORD PTR [rsp+0x20]
  400b17:       0f 84 65 01 00 00       je     400c82 <main+0x2a2>
  400b1d:       48 85 c0                test   rax,rax
  400b20:       8b 4c 24 0c             mov    ecx,DWORD PTR [rsp+0xc]
  400b24:       74 06                   je     400b2c <main+0x14c>
  400b26:       89 08                   mov    DWORD PTR [rax],ecx
  400b28:       8b 4c 24 0c             mov    ecx,DWORD PTR [rsp+0xc]
  400b2c:       83 c1 01                add    ecx,0x1
  400b2f:       48 83 c0 04             add    rax,0x4
  400b33:       81 f9 ff ff 00 00       cmp    ecx,0xffff
  400b39:       48 89 44 24 18          mov    QWORD PTR [rsp+0x18],rax
  400b3e:       89 4c 24 0c             mov    DWORD PTR [rsp+0xc],ecx
  400b42:       0f 86 65 ff ff ff       jbe    400aad <main+0xcd>
  400b48:       bb 00 00 01 00          mov    ebx,0x10000
  400b4d:       45 31 e4                xor    r12d,r12d
  400b50:       4c 8b 4c 24 10          mov    r9,QWORD PTR [rsp+0x10]
  400b55:       4c 8b 54 24 18          mov    r10,QWORD PTR [rsp+0x18]
  400b5a:       b9 00 04 00 00          mov    ecx,0x400
  400b5f:       48 89 ef                mov    rdi,rbp
  400b62:       4c 89 e0                mov    rax,r12
  400b65:       f3 48 ab                rep stos QWORD PTR es:[rdi],rax
  400b68:       4d 39 d1                cmp    r9,r10
  400b6b:       0f 84 76 01 00 00       je     400ce7 <main+0x307>
  400b71:       41 b8 01 00 00 00       mov    r8d,0x1
  400b77:       66 0f 1f 84 00 00 00    nop    WORD PTR [rax+rax*1+0x0]
  400b7e:       00 00
  400b80:       41 8b 39                mov    edi,DWORD PTR [r9]
  400b83:       31 d2                   xor    edx,edx
  400b85:       89 d8                   mov    eax,ebx
  400b87:       f7 f7                   div    edi
  400b89:       89 f8                   mov    eax,edi
  400b8b:       29 d0                   sub    eax,edx
  400b8d:       31 d2                   xor    edx,edx
  400b8f:       f7 f7                   div    edi
  400b91:       89 d1                   mov    ecx,edx
  400b93:       8d 14 1a                lea    edx,[rdx+rbx*1]
  400b96:       81 f9 ff ff 00 00       cmp    ecx,0xffff
  400b9c:       89 54 24 0c             mov    DWORD PTR [rsp+0xc],edx
  400ba0:       77 29                   ja     400bcb <main+0x1eb>
  400ba2:       66 0f 1f 44 00 00       nop    WORD PTR [rax+rax*1+0x0]
  400ba8:       01 fa                   add    edx,edi
  400baa:       4c 89 c0                mov    rax,r8
  400bad:       89 ce                   mov    esi,ecx
  400baf:       48 d3 e0                shl    rax,cl
  400bb2:       89 d1                   mov    ecx,edx
  400bb4:       48 c1 ee 06             shr    rsi,0x6
  400bb8:       29 d9                   sub    ecx,ebx
  400bba:       48 09 44 f4 30          or     QWORD PTR [rsp+rsi*8+0x30],rax
  400bbf:       89 54 24 0c             mov    DWORD PTR [rsp+0xc],edx
  400bc3:       81 f9 ff ff 00 00       cmp    ecx,0xffff
  400bc9:       76 dd                   jbe    400ba8 <main+0x1c8>
  400bcb:       49 83 c1 04             add    r9,0x4
  400bcf:       4d 39 ca                cmp    r10,r9
  400bd2:       75 ac                   jne    400b80 <main+0x1a0>
  400bd4:       48 8b 44 24 30          mov    rax,QWORD PTR [rsp+0x30]
  400bd9:       c7 44 24 0c 00 00 00    mov    DWORD PTR [rsp+0xc],0x0
  400be0:       00
  400be1:       31 c9                   xor    ecx,ecx
  400be3:       41 bd 01 00 00 00       mov    r13d,0x1
  400be9:       eb 27                   jmp    400c12 <main+0x232>
  400beb:       0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]
  400bf0:       8b 44 24 0c             mov    eax,DWORD PTR [rsp+0xc]
  400bf4:       8d 48 01                lea    ecx,[rax+0x1]
  400bf7:       81 f9 ff ff 00 00       cmp    ecx,0xffff
  400bfd:       89 4c 24 0c             mov    DWORD PTR [rsp+0xc],ecx
  400c01:       0f 87 b1 00 00 00       ja     400cb8 <main+0x2d8>
  400c07:       89 c8                   mov    eax,ecx
  400c09:       48 c1 e8 06             shr    rax,0x6
  400c0d:       48 8b 44 c4 30          mov    rax,QWORD PTR [rsp+rax*8+0x30]
  400c12:       4c 89 ea                mov    rdx,r13
  400c15:       48 d3 e2                shl    rdx,cl
  400c18:       48 85 d0                test   rax,rdx
  400c1b:       75 d3                   jne    400bf0 <main+0x210>
  400c1d:       8d 34 19                lea    esi,[rcx+rbx*1]
  400c20:       bf a0 20 60 00          mov    edi,0x6020a0
  400c25:       e8 66 fd ff ff          call   400990 <std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<unsigned long>(unsigned long)@plt>
  400c2a:       49 89 c7                mov    r15,rax
  400c2d:       48 8b 00                mov    rax,QWORD PTR [rax]
  400c30:       48 8b 40 e8             mov    rax,QWORD PTR [rax-0x18]
  400c34:       4d 8b b4 07 f0 00 00    mov    r14,QWORD PTR [r15+rax*1+0xf0]
  400c3b:       00
  400c3c:       4d 85 f6                test   r14,r14
  400c3f:       0f 84 b1 00 00 00       je     400cf6 <main+0x316>
  400c45:       41 80 7e 38 00          cmp    BYTE PTR [r14+0x38],0x0
  400c4a:       74 54                   je     400ca0 <main+0x2c0>
  400c4c:       41 0f b6 46 43          movzx  eax,BYTE PTR [r14+0x43]
  400c51:       0f be f0                movsx  esi,al
  400c54:       4c 89 ff                mov    rdi,r15
  400c57:       e8 74 fd ff ff          call   4009d0 <std::basic_ostream<char, std::char_traits<char> >::put(char)@plt>
  400c5c:       48 89 c7                mov    rdi,rax
  400c5f:       e8 1c fd ff ff          call   400980 <std::basic_ostream<char, std::char_traits<char> >::flush()@plt>
  400c64:       eb 8a                   jmp    400bf0 <main+0x210>
  400c66:       4c 89 e7                mov    rdi,r12
  400c69:       e8 b2 fc ff ff          call   400920 <std::ctype<char>::_M_widen_init() const@plt>
  400c6e:       49 8b 04 24             mov    rax,QWORD PTR [r12]
  400c72:       be 0a 00 00 00          mov    esi,0xa
  400c77:       4c 89 e7                mov    rdi,r12
  400c7a:       ff 50 30                call   QWORD PTR [rax+0x30]
  400c7d:       e9 78 fe ff ff          jmp    400afa <main+0x11a>
  400c82:       48 8d 74 24 0c          lea    rsi,[rsp+0xc]
  400c87:       48 8d 7c 24 10          lea    rdi,[rsp+0x10]
  400c8c:       e8 9f 01 00 00          call   400e30 <void std::vector<unsigned int, std::allocator<unsigned int> >::_M_emplace_back_aux<unsigned int const&>(unsigned int const&)>
  400c91:       e9 00 fe ff ff          jmp    400a96 <main+0xb6>
  400c96:       66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
  400c9d:       00 00 00
  400ca0:       4c 89 f7                mov    rdi,r14
  400ca3:       e8 78 fc ff ff          call   400920 <std::ctype<char>::_M_widen_init() const@plt>
  400ca8:       49 8b 06                mov    rax,QWORD PTR [r14]
  400cab:       be 0a 00 00 00          mov    esi,0xa
  400cb0:       4c 89 f7                mov    rdi,r14
  400cb3:       ff 50 30                call   QWORD PTR [rax+0x30]
  400cb6:       eb 99                   jmp    400c51 <main+0x271>
  400cb8:       81 c3 00 00 01 00       add    ebx,0x10000
  400cbe:       0f 85 8c fe ff ff       jne    400b50 <main+0x170>
  400cc4:       48 8b 7c 24 10          mov    rdi,QWORD PTR [rsp+0x10]
  400cc9:       48 85 ff                test   rdi,rdi
  400ccc:       74 05                   je     400cd3 <main+0x2f3>
  400cce:       e8 3d fc ff ff          call   400910 <operator delete(void*)@plt>
  400cd3:       48 81 c4 38 20 00 00    add    rsp,0x2038
  400cda:       31 c0                   xor    eax,eax
  400cdc:       5b                      pop    rbx
  400cdd:       5d                      pop    rbp
  400cde:       41 5c                   pop    r12
  400ce0:       41 5d                   pop    r13
  400ce2:       41 5e                   pop    r14
  400ce4:       41 5f                   pop    r15
  400ce6:       c3                      ret
  400ce7:       c7 44 24 0c 00 00 00    mov    DWORD PTR [rsp+0xc],0x0
  400cee:       00
  400cef:       31 c0                   xor    eax,eax
  400cf1:       e9 eb fe ff ff          jmp    400be1 <main+0x201>
  400cf6:       e8 f5 fb ff ff          call   4008f0 <std::__throw_bad_cast()@plt>
  400cfb:       e8 f0 fb ff ff          call   4008f0 <std::__throw_bad_cast()@plt>
  400d00:       48 8b 7c 24 10          mov    rdi,QWORD PTR [rsp+0x10]
  400d05:       48 89 c3                mov    rbx,rax
  400d08:       48 85 ff                test   rdi,rdi
  400d0b:       74 05                   je     400d12 <main+0x332>
  400d0d:       e8 fe fb ff ff          call   400910 <operator delete(void*)@plt>
  400d12:       48 89 df                mov    rdi,rbx
  400d15:       e8 a6 fc ff ff          call   4009c0 <_Unwind_Resume@plt>
  400d1a:       66 0f 1f 44 00 00       nop    WORD PTR [rax+rax*1+0x0]
$ objdump -d sieve_go | c++filt | awk '/<main/,/^$/'
0000000000401000 <main.main>:
  401000:       64 48 8b 0c 25 f8 ff    mov    rcx,QWORD PTR fs:0xfffffffffffffff8
  401007:       ff ff
  401009:       48 8b 71 10             mov    rsi,QWORD PTR [rcx+0x10]
  40100d:       48 81 fe de fa ff ff    cmp    rsi,0xfffffffffffffade
  401014:       0f 84 de 04 00 00       je     4014f8 <main.main+0x4f8>
  40101a:       48 8d 84 24 d0 02 00    lea    rax,[rsp+0x2d0]
  401021:       00
  401022:       48 29 f0                sub    rax,rsi
  401025:       48 3d 08 03 01 00       cmp    rax,0x10308
  40102b:       0f 86 c7 04 00 00       jbe    4014f8 <main.main+0x4f8>
  401031:       48 81 ec b8 00 01 00    sub    rsp,0x100b8
  401038:       0f 57 c0                xorps  xmm0,xmm0
  40103b:       0f 11 84 24 58 00 01    movups XMMWORD PTR [rsp+0x10058],xmm0
  401042:       00
  401043:       0f 11 84 24 68 00 01    movups XMMWORD PTR [rsp+0x10068],xmm0
  40104a:       00
  40104b:       0f 11 84 24 78 00 01    movups XMMWORD PTR [rsp+0x10078],xmm0
  401052:       00
  401053:       48 8d 7c 24 58          lea    rdi,[rsp+0x58]
  401058:       31 c0                   xor    eax,eax
  40105a:       48 c7 c1 00 20 00 00    mov    rcx,0x2000
  401061:       f3 48 ab                rep stos QWORD PTR es:[rdi],rax
  401064:       31 db                   xor    ebx,ebx
  401066:       48 8d 5c 24 40          lea    rbx,[rsp+0x40]
  40106b:       48 83 fb 00             cmp    rbx,0x0
  40106f:       0f 84 7c 04 00 00       je     4014f1 <main.main+0x4f1>
  401075:       48 c7 84 24 90 00 01    mov    QWORD PTR [rsp+0x10090],0x0
  40107c:       00 00 00 00 00
  401081:       48 c7 84 24 98 00 01    mov    QWORD PTR [rsp+0x10098],0x0
  401088:       00 00 00 00 00
  40108d:       48 89 9c 24 88 00 01    mov    QWORD PTR [rsp+0x10088],rbx
  401094:       00
  401095:       48 c7 c1 02 00 00 00    mov    rcx,0x2
  40109c:       48 81 f9 00 01 00 00    cmp    rcx,0x100
  4010a3:       7d 2e                   jge    4010d3 <main.main+0xd3>
  4010a5:       48 8d 5c 24 58          lea    rbx,[rsp+0x58]
  4010aa:       48 81 f9 00 00 01 00    cmp    rcx,0x10000
  4010b1:       0f 83 33 04 00 00       jae    4014ea <main.main+0x4ea>
  4010b7:       48 8d 1c 0b             lea    rbx,[rbx+rcx*1]
  4010bb:       0f b6 1b                movzx  ebx,BYTE PTR [rbx]
  4010be:       80 fb 00                cmp    bl,0x0
  4010c1:       0f 84 f1 03 00 00       je     4014b8 <main.main+0x4b8>
  4010c7:       48 ff c1                inc    rcx
  4010ca:       48 81 f9 00 01 00 00    cmp    rcx,0x100
  4010d1:       7c d2                   jl     4010a5 <main.main+0xa5>
  4010d3:       ba 02 00 00 00          mov    edx,0x2
  4010d8:       81 fa 00 00 01 00       cmp    edx,0x10000
  4010de:       0f 83 3b 01 00 00       jae    40121f <main.main+0x21f>
  4010e4:       48 8d 5c 24 58          lea    rbx,[rsp+0x58]
  4010e9:       8b ea                   mov    ebp,edx
  4010eb:       48 81 fd 00 00 01 00    cmp    rbp,0x10000
  4010f2:       0f 83 b9 03 00 00       jae    4014b1 <main.main+0x4b1>
  4010f8:       48 8d 1c 2b             lea    rbx,[rbx+rbp*1]
  4010fc:       0f b6 1b                movzx  ebx,BYTE PTR [rbx]
  4010ff:       80 fb 00                cmp    bl,0x0
  401102:       0f 85 09 01 00 00       jne    401211 <main.main+0x211>
  401108:       89 54 24 48             mov    DWORD PTR [rsp+0x48],edx
  40110c:       89 54 24 4c             mov    DWORD PTR [rsp+0x4c],edx
  401110:       31 db                   xor    ebx,ebx
  401112:       48 89 9c 24 78 00 01    mov    QWORD PTR [rsp+0x10078],rbx
  401119:       00
  40111a:       48 89 9c 24 80 00 01    mov    QWORD PTR [rsp+0x10080],rbx
  401121:       00
  401122:       48 8d 9c 24 78 00 01    lea    rbx,[rsp+0x10078]
  401129:       00
  40112a:       48 83 fb 00             cmp    rbx,0x0
  40112e:       0f 84 76 03 00 00       je     4014aa <main.main+0x4aa>
  401134:       48 c7 84 24 a8 00 01    mov    QWORD PTR [rsp+0x100a8],0x1
  40113b:       00 01 00 00 00
  401140:       48 c7 84 24 b0 00 01    mov    QWORD PTR [rsp+0x100b0],0x1
  401147:       00 01 00 00 00
  40114c:       48 89 9c 24 a0 00 01    mov    QWORD PTR [rsp+0x100a0],rbx
  401153:       00
  401154:       48 8d 1d e5 7e 0b 00    lea    rbx,[rip+0xb7ee5]        # 4b9040 <type.*+0xe040>
  40115b:       48 89 1c 24             mov    QWORD PTR [rsp],rbx
  40115f:       48 8d 5c 24 4c          lea    rbx,[rsp+0x4c]
  401164:       48 89 5c 24 08          mov    QWORD PTR [rsp+0x8],rbx
  401169:       48 c7 44 24 10 00 00    mov    QWORD PTR [rsp+0x10],0x0
  401170:       00 00
  401172:       e8 89 ac 00 00          call   40be00 <runtime.convT2E>
  401177:       48 8b 4c 24 18          mov    rcx,QWORD PTR [rsp+0x18]
  40117c:       48 8b 44 24 20          mov    rax,QWORD PTR [rsp+0x20]
  401181:       48 8b 9c 24 a0 00 01    mov    rbx,QWORD PTR [rsp+0x100a0]
  401188:       00
  401189:       48 89 8c 24 68 00 01    mov    QWORD PTR [rsp+0x10068],rcx
  401190:       00
  401191:       48 89 0b                mov    QWORD PTR [rbx],rcx
  401194:       48 89 84 24 70 00 01    mov    QWORD PTR [rsp+0x10070],rax
  40119b:       00
  40119c:       80 3d 3d e9 19 00 00    cmp    BYTE PTR [rip+0x19e93d],0x0        # 59fae0 <runtime.writeBarrier>
  4011a3:       0f 85 ea 02 00 00       jne    401493 <main.main+0x493>
  4011a9:       48 89 43 08             mov    QWORD PTR [rbx+0x8],rax
  4011ad:       48 8b 9c 24 a0 00 01    mov    rbx,QWORD PTR [rsp+0x100a0]
  4011b4:       00
  4011b5:       48 89 1c 24             mov    QWORD PTR [rsp],rbx
  4011b9:       48 8b 9c 24 a8 00 01    mov    rbx,QWORD PTR [rsp+0x100a8]
  4011c0:       00
  4011c1:       48 89 5c 24 08          mov    QWORD PTR [rsp+0x8],rbx
  4011c6:       48 8b 9c 24 b0 00 01    mov    rbx,QWORD PTR [rsp+0x100b0]
  4011cd:       00
  4011ce:       48 89 5c 24 10          mov    QWORD PTR [rsp+0x10],rbx
  4011d3:       e8 b8 98 05 00          call   45aa90 <fmt.Println>
  4011d8:       8b 54 24 48             mov    edx,DWORD PTR [rsp+0x48]
  4011dc:       48 8b 8c 24 88 00 01    mov    rcx,QWORD PTR [rsp+0x10088]
  4011e3:       00
  4011e4:       48 8b 9c 24 90 00 01    mov    rbx,QWORD PTR [rsp+0x10090]
  4011eb:       00
  4011ec:       48 8b b4 24 98 00 01    mov    rsi,QWORD PTR [rsp+0x10098]
  4011f3:       00
  4011f4:       48 89 d8                mov    rax,rbx
  4011f7:       48 ff c3                inc    rbx
  4011fa:       48 39 f3                cmp    rbx,rsi
  4011fd:       0f 87 36 02 00 00       ja     401439 <main.main+0x439>
  401203:       48 89 9c 24 90 00 01    mov    QWORD PTR [rsp+0x10090],rbx
  40120a:       00
  40120b:       48 8d 1c 81             lea    rbx,[rcx+rax*4]
  40120f:       89 13                   mov    DWORD PTR [rbx],edx
  401211:       ff c2                   inc    edx
  401213:       81 fa 00 00 01 00       cmp    edx,0x10000
  401219:       0f 82 c5 fe ff ff       jb     4010e4 <main.main+0xe4>
  40121f:       48 c7 c0 01 00 00 00    mov    rax,0x1
  401226:       48 89 44 24 50          mov    QWORD PTR [rsp+0x50],rax
  40122b:       48 3d 00 00 01 00       cmp    rax,0x10000
  401231:       0f 8d d1 01 00 00       jge    401408 <main.main+0x408>
  401237:       48 8d 5c 24 58          lea    rbx,[rsp+0x58]
  40123c:       48 c7 c0 00 00 01 00    mov    rax,0x10000
  401243:       48 89 1c 24             mov    QWORD PTR [rsp],rbx
  401247:       48 89 44 24 08          mov    QWORD PTR [rsp+0x8],rax
  40124c:       e8 3f 4e 05 00          call   456090 <runtime.memclr>
  401251:       48 8b 74 24 50          mov    rsi,QWORD PTR [rsp+0x50]
  401256:       48 c1 e6 10             shl    rsi,0x10
  40125a:       89 f6                   mov    esi,esi
  40125c:       48 8b bc 24 88 00 01    mov    rdi,QWORD PTR [rsp+0x10088]
  401263:       00
  401264:       4c 8b 8c 24 90 00 01    mov    r9,QWORD PTR [rsp+0x10090]
  40126b:       00
  40126c:       48 8b 9c 24 98 00 01    mov    rbx,QWORD PTR [rsp+0x10098]
  401273:       00
  401274:       45 31 c0                xor    r8d,r8d
  401277:       4d 39 c8                cmp    r8,r9
  40127a:       7d 59                   jge    4012d5 <main.main+0x2d5>
  40127c:       8b 0f                   mov    ecx,DWORD PTR [rdi]
  40127e:       89 f0                   mov    eax,esi
  401280:       31 d2                   xor    edx,edx
  401282:       f7 f1                   div    ecx
  401284:       89 c8                   mov    eax,ecx
  401286:       29 d0                   sub    eax,edx
  401288:       31 d2                   xor    edx,edx
  40128a:       f7 f1                   div    ecx
  40128c:       89 d0                   mov    eax,edx
  40128e:       01 f0                   add    eax,esi
  401290:       89 c3                   mov    ebx,eax
  401292:       29 f3                   sub    ebx,esi
  401294:       81 fb 00 00 01 00       cmp    ebx,0x10000
  40129a:       73 2d                   jae    4012c9 <main.main+0x2c9>
  40129c:       89 c2                   mov    edx,eax
  40129e:       29 f2                   sub    edx,esi
  4012a0:       48 8d 5c 24 58          lea    rbx,[rsp+0x58]
  4012a5:       8b ea                   mov    ebp,edx
  4012a7:       48 81 fd 00 00 01 00    cmp    rbp,0x10000
  4012ae:       0f 83 7e 01 00 00       jae    401432 <main.main+0x432>
  4012b4:       48 8d 1c 2b             lea    rbx,[rbx+rbp*1]
  4012b8:       c6 03 01                mov    BYTE PTR [rbx],0x1
  4012bb:       01 c8                   add    eax,ecx
  4012bd:       89 c3                   mov    ebx,eax
  4012bf:       29 f3                   sub    ebx,esi
  4012c1:       81 fb 00 00 01 00       cmp    ebx,0x10000
  4012c7:       72 d3                   jb     40129c <main.main+0x29c>
  4012c9:       48 83 c7 04             add    rdi,0x4
  4012cd:       49 ff c0                inc    r8
  4012d0:       4d 39 c8                cmp    r8,r9
  4012d3:       7c a7                   jl     40127c <main.main+0x27c>
  4012d5:       31 c0                   xor    eax,eax
  4012d7:       3d 00 00 01 00          cmp    eax,0x10000
  4012dc:       0f 83 0d 01 00 00       jae    4013ef <main.main+0x3ef>
  4012e2:       48 8d 5c 24 58          lea    rbx,[rsp+0x58]
  4012e7:       8b e8                   mov    ebp,eax
  4012e9:       48 81 fd 00 00 01 00    cmp    rbp,0x10000
  4012f0:       0f 83 35 01 00 00       jae    40142b <main.main+0x42b>
  4012f6:       48 8d 1c 2b             lea    rbx,[rbx+rbp*1]
  4012fa:       0f b6 1b                movzx  ebx,BYTE PTR [rbx]
  4012fd:       80 fb 00                cmp    bl,0x0
  401300:       0f 85 dc 00 00 00       jne    4013e2 <main.main+0x3e2>
  401306:       89 f3                   mov    ebx,esi
  401308:       89 74 24 40             mov    DWORD PTR [rsp+0x40],esi
  40130c:       89 44 24 44             mov    DWORD PTR [rsp+0x44],eax
  401310:       01 c3                   add    ebx,eax
  401312:       89 5c 24 4c             mov    DWORD PTR [rsp+0x4c],ebx
  401316:       31 db                   xor    ebx,ebx
  401318:       48 89 9c 24 58 00 01    mov    QWORD PTR [rsp+0x10058],rbx
  40131f:       00
  401320:       48 89 9c 24 60 00 01    mov    QWORD PTR [rsp+0x10060],rbx
  401327:       00
  401328:       48 8d 9c 24 58 00 01    lea    rbx,[rsp+0x10058]
  40132f:       00
  401330:       48 83 fb 00             cmp    rbx,0x0
  401334:       0f 84 ea 00 00 00       je     401424 <main.main+0x424>
  40133a:       48 c7 84 24 a8 00 01    mov    QWORD PTR [rsp+0x100a8],0x1
  401341:       00 01 00 00 00
  401346:       48 c7 84 24 b0 00 01    mov    QWORD PTR [rsp+0x100b0],0x1
  40134d:       00 01 00 00 00
  401352:       48 89 9c 24 a0 00 01    mov    QWORD PTR [rsp+0x100a0],rbx
  401359:       00
  40135a:       48 8d 1d df 7c 0b 00    lea    rbx,[rip+0xb7cdf]        # 4b9040 <type.*+0xe040>
  401361:       48 89 1c 24             mov    QWORD PTR [rsp],rbx
  401365:       48 8d 5c 24 4c          lea    rbx,[rsp+0x4c]
  40136a:       48 89 5c 24 08          mov    QWORD PTR [rsp+0x8],rbx
  40136f:       48 c7 44 24 10 00 00    mov    QWORD PTR [rsp+0x10],0x0
  401376:       00 00
  401378:       e8 83 aa 00 00          call   40be00 <runtime.convT2E>
  40137d:       48 8b 4c 24 18          mov    rcx,QWORD PTR [rsp+0x18]
  401382:       48 8b 44 24 20          mov    rax,QWORD PTR [rsp+0x20]
  401387:       48 8b 9c 24 a0 00 01    mov    rbx,QWORD PTR [rsp+0x100a0]
  40138e:       00
  40138f:       48 89 8c 24 68 00 01    mov    QWORD PTR [rsp+0x10068],rcx
  401396:       00
  401397:       48 89 0b                mov    QWORD PTR [rbx],rcx
  40139a:       48 89 84 24 70 00 01    mov    QWORD PTR [rsp+0x10070],rax
  4013a1:       00
  4013a2:       80 3d 37 e7 19 00 00    cmp    BYTE PTR [rip+0x19e737],0x0        # 59fae0 <runtime.writeBarrier>
  4013a9:       75 65                   jne    401410 <main.main+0x410>
  4013ab:       48 89 43 08             mov    QWORD PTR [rbx+0x8],rax
  4013af:       48 8b 9c 24 a0 00 01    mov    rbx,QWORD PTR [rsp+0x100a0]
  4013b6:       00
  4013b7:       48 89 1c 24             mov    QWORD PTR [rsp],rbx
  4013bb:       48 8b 9c 24 a8 00 01    mov    rbx,QWORD PTR [rsp+0x100a8]
  4013c2:       00
  4013c3:       48 89 5c 24 08          mov    QWORD PTR [rsp+0x8],rbx
  4013c8:       48 8b 9c 24 b0 00 01    mov    rbx,QWORD PTR [rsp+0x100b0]
  4013cf:       00
  4013d0:       48 89 5c 24 10          mov    QWORD PTR [rsp+0x10],rbx
  4013d5:       e8 b6 96 05 00          call   45aa90 <fmt.Println>
  4013da:       8b 44 24 44             mov    eax,DWORD PTR [rsp+0x44]
  4013de:       8b 74 24 40             mov    esi,DWORD PTR [rsp+0x40]
  4013e2:       ff c0                   inc    eax
  4013e4:       3d 00 00 01 00          cmp    eax,0x10000
  4013e9:       0f 82 f3 fe ff ff       jb     4012e2 <main.main+0x2e2>
  4013ef:       48 8b 44 24 50          mov    rax,QWORD PTR [rsp+0x50]
  4013f4:       48 ff c0                inc    rax
  4013f7:       48 89 44 24 50          mov    QWORD PTR [rsp+0x50],rax
  4013fc:       48 3d 00 00 01 00       cmp    rax,0x10000
  401402:       0f 8c 2f fe ff ff       jl     401237 <main.main+0x237>
  401408:       48 81 c4 b8 00 01 00    add    rsp,0x100b8
  40140f:       c3                      ret
  401410:       4c 8d 43 08             lea    r8,[rbx+0x8]
  401414:       4c 89 04 24             mov    QWORD PTR [rsp],r8
  401418:       48 89 44 24 08          mov    QWORD PTR [rsp+0x8],rax
  40141d:       e8 de de 00 00          call   40f300 <runtime.writebarrierptr>
  401422:       eb 8b                   jmp    4013af <main.main+0x3af>
  401424:       89 03                   mov    DWORD PTR [rbx],eax
  401426:       e9 0f ff ff ff          jmp    40133a <main.main+0x33a>
  40142b:       e8 a0 53 02 00          call   4267d0 <runtime.panicindex>
  401430:       0f 0b                   ud2
  401432:       e8 99 53 02 00          call   4267d0 <runtime.panicindex>
  401437:       0f 0b                   ud2
  401439:       48 8d 2d 00 31 0b 00    lea    rbp,[rip+0xb3100]        # 4b4540 <type.*+0x9540>
  401440:       48 89 2c 24             mov    QWORD PTR [rsp],rbp
  401444:       48 89 4c 24 08          mov    QWORD PTR [rsp+0x8],rcx
  401449:       48 89 44 24 10          mov    QWORD PTR [rsp+0x10],rax
  40144e:       48 89 74 24 18          mov    QWORD PTR [rsp+0x18],rsi
  401453:       48 89 5c 24 20          mov    QWORD PTR [rsp+0x20],rbx
  401458:       e8 e3 9b 03 00          call   43b040 <runtime.growslice>
  40145d:       8b 54 24 48             mov    edx,DWORD PTR [rsp+0x48]
  401461:       48 8b 4c 24 28          mov    rcx,QWORD PTR [rsp+0x28]
  401466:       48 8b 5c 24 30          mov    rbx,QWORD PTR [rsp+0x30]
  40146b:       48 8b 6c 24 38          mov    rbp,QWORD PTR [rsp+0x38]
  401470:       48 89 d8                mov    rax,rbx
  401473:       48 ff c3                inc    rbx
  401476:       48 89 9c 24 90 00 01    mov    QWORD PTR [rsp+0x10090],rbx
  40147d:       00
  40147e:       48 89 ac 24 98 00 01    mov    QWORD PTR [rsp+0x10098],rbp
  401485:       00
  401486:       48 89 8c 24 88 00 01    mov    QWORD PTR [rsp+0x10088],rcx
  40148d:       00
  40148e:       e9 78 fd ff ff          jmp    40120b <main.main+0x20b>
  401493:       4c 8d 43 08             lea    r8,[rbx+0x8]
  401497:       4c 89 04 24             mov    QWORD PTR [rsp],r8
  40149b:       48 89 44 24 08          mov    QWORD PTR [rsp+0x8],rax
  4014a0:       e8 5b de 00 00          call   40f300 <runtime.writebarrierptr>
  4014a5:       e9 03 fd ff ff          jmp    4011ad <main.main+0x1ad>
  4014aa:       89 03                   mov    DWORD PTR [rbx],eax
  4014ac:       e9 83 fc ff ff          jmp    401134 <main.main+0x134>
  4014b1:       e8 1a 53 02 00          call   4267d0 <runtime.panicindex>
  4014b6:       0f 0b                   ud2
  4014b8:       48 89 c8                mov    rax,rcx
  4014bb:       48 d1 e0                shl    rax,1
  4014be:       48 3d 00 00 01 00       cmp    rax,0x10000
  4014c4:       0f 8d fd fb ff ff       jge    4010c7 <main.main+0xc7>
  4014ca:       48 8d 5c 24 58          lea    rbx,[rsp+0x58]
  4014cf:       48 3d 00 00 01 00       cmp    rax,0x10000
  4014d5:       73 0c                   jae    4014e3 <main.main+0x4e3>
  4014d7:       48 8d 1c 03             lea    rbx,[rbx+rax*1]
  4014db:       c6 03 01                mov    BYTE PTR [rbx],0x1
  4014de:       48 01 c8                add    rax,rcx
  4014e1:       eb db                   jmp    4014be <main.main+0x4be>
  4014e3:       e8 e8 52 02 00          call   4267d0 <runtime.panicindex>
  4014e8:       0f 0b                   ud2
  4014ea:       e8 e1 52 02 00          call   4267d0 <runtime.panicindex>
  4014ef:       0f 0b                   ud2
  4014f1:       89 03                   mov    DWORD PTR [rbx],eax
  4014f3:       e9 7d fb ff ff          jmp    401075 <main.main+0x75>
  4014f8:       e8 03 21 05 00          call   453600 <runtime.morestack_noctxt>
  4014fd:       e9 fe fa ff ff          jmp    401000 <main.main>
  401502:       cc                      int3
  401503:       cc                      int3
  401504:       cc                      int3
  401505:       cc                      int3
  401506:       cc                      int3
  401507:       cc                      int3
  401508:       cc                      int3
  401509:       cc                      int3
  40150a:       cc                      int3
  40150b:       cc                      int3
  40150c:       cc                      int3
  40150d:       cc                      int3
  40150e:       cc                      int3
  40150f:       cc                      int3
$ objdump -d sieve_rs | c++filt | awk '/<main/,/^$/'
0000000000004cb0 <main::h3a7d143d57a98e1aeaa>:
    4cb0:       55                      push   rbp
    4cb1:       41 57                   push   r15
    4cb3:       41 56                   push   r14
    4cb5:       41 55                   push   r13
    4cb7:       41 54                   push   r12
    4cb9:       53                      push   rbx
    4cba:       48 81 ec c8 00 01 00    sub    rsp,0x100c8
    4cc1:       48 b8 1d 1d 1d 1d 1d    movabs rax,0x1d1d1d1d1d1d1d1d
    4cc8:       1d 1d 1d
    4ccb:       48 89 44 24 20          mov    QWORD PTR [rsp+0x20],rax
    4cd0:       48 8d bc 24 c8 00 00    lea    rdi,[rsp+0xc8]
    4cd7:       00
    4cd8:       31 f6                   xor    esi,esi
    4cda:       ba 00 00 01 00          mov    edx,0x10000
    4cdf:       e8 8c fa ff ff          call   4770 <memset@plt>
    4ce4:       48 c7 84 24 b0 00 00    mov    QWORD PTR [rsp+0xb0],0x1
    4ceb:       00 01 00 00 00
    4cf0:       0f 57 c0                xorps  xmm0,xmm0
    4cf3:       0f 11 84 24 b8 00 00    movups XMMWORD PTR [rsp+0xb8],xmm0
    4cfa:       00
    4cfb:       b8 02 00 00 00          mov    eax,0x2
    4d00:       48 89 c1                mov    rcx,rax
    4d03:       48 83 c9 01             or     rcx,0x1
    4d07:       80 bc 04 c8 00 00 00    cmp    BYTE PTR [rsp+rax*1+0xc8],0x0
    4d0e:       00
    4d0f:       75 23                   jne    4d34 <main::h3a7d143d57a98e1aeaa+0x84>
    4d11:       48 8d 14 00             lea    rdx,[rax+rax*1]
    4d15:       66 66 2e 0f 1f 84 00    data32 nop WORD PTR cs:[rax+rax*1+0x0]
    4d1c:       00 00 00 00
    4d20:       c6 84 14 c8 00 00 00    mov    BYTE PTR [rsp+rdx*1+0xc8],0x1
    4d27:       01
    4d28:       48 01 c2                add    rdx,rax
    4d2b:       48 81 fa 00 00 01 00    cmp    rdx,0x10000
    4d32:       72 ec                   jb     4d20 <main::h3a7d143d57a98e1aeaa+0x70>
    4d34:       48 83 c0 02             add    rax,0x2
    4d38:       80 bc 0c c8 00 00 00    cmp    BYTE PTR [rsp+rcx*1+0xc8],0x0
    4d3f:       00
    4d40:       75 22                   jne    4d64 <main::h3a7d143d57a98e1aeaa+0xb4>
    4d42:       48 8d 14 09             lea    rdx,[rcx+rcx*1]
    4d46:       66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
    4d4d:       00 00 00
    4d50:       c6 84 14 c8 00 00 00    mov    BYTE PTR [rsp+rdx*1+0xc8],0x1
    4d57:       01
    4d58:       48 01 ca                add    rdx,rcx
    4d5b:       48 81 fa 00 00 01 00    cmp    rdx,0x10000
    4d62:       72 ec                   jb     4d50 <main::h3a7d143d57a98e1aeaa+0xa0>
    4d64:       48 3d 00 01 00 00       cmp    rax,0x100
    4d6a:       75 94                   jne    4d00 <main::h3a7d143d57a98e1aeaa+0x50>
    4d6c:       bd 02 00 00 00          mov    ebp,0x2
    4d71:       45 31 e4                xor    r12d,r12d
    4d74:       41 bf 01 00 00 00       mov    r15d,0x1
    4d7a:       4c 8d 6c 24 68          lea    r13,[rsp+0x68]
    4d7f:       48 8d 5c 24 78          lea    rbx,[rsp+0x78]
    4d84:       66 66 66 2e 0f 1f 84    data32 data32 nop WORD PTR cs:[rax+rax*1+0x0]
    4d8b:       00 00 00 00 00
    4d90:       48 89 ac 24 a8 00 00    mov    QWORD PTR [rsp+0xa8],rbp
    4d97:       00
    4d98:       80 bc 2c c8 00 00 00    cmp    BYTE PTR [rsp+rbp*1+0xc8],0x0
    4d9f:       00
    4da0:       0f 85 a1 00 00 00       jne    4e47 <main::h3a7d143d57a98e1aeaa+0x197>
    4da6:       48 8d 05 03 72 03 00    lea    rax,[rip+0x37203]        # 3bfb0 <fmt::num::usize.fmt..Display::fmt::h841af16830bb5f60kgW>
    4dad:       48 89 44 24 70          mov    QWORD PTR [rsp+0x70],rax
    4db2:       48 8d 84 24 a8 00 00    lea    rax,[rsp+0xa8]
    4db9:       00
    4dba:       48 89 44 24 68          mov    QWORD PTR [rsp+0x68],rax
    4dbf:       48 8d 05 d2 84 24 00    lea    rax,[rip+0x2484d2]        # 24d298 <ref4653>
    4dc6:       48 89 44 24 78          mov    QWORD PTR [rsp+0x78],rax
    4dcb:       48 c7 84 24 80 00 00    mov    QWORD PTR [rsp+0x80],0x2
    4dd2:       00 02 00 00 00
    4dd7:       48 8d 84 24 88 00 00    lea    rax,[rsp+0x88]
    4dde:       00
    4ddf:       0f 57 c0                xorps  xmm0,xmm0
    4de2:       0f 11 00                movups XMMWORD PTR [rax],xmm0
    4de5:       4c 89 ac 24 98 00 00    mov    QWORD PTR [rsp+0x98],r13
    4dec:       00
    4ded:       48 c7 84 24 a0 00 00    mov    QWORD PTR [rsp+0xa0],0x1
    4df4:       00 01 00 00 00
    4df9:       48 89 df                mov    rdi,rbx
    4dfc:       e8 5f 2f 00 00          call   7d60 <io::stdio::_print::h27ae99cc97e67314Erh>
    4e01:       4c 8b b4 24 a8 00 00    mov    r14,QWORD PTR [rsp+0xa8]
    4e08:       00
    4e09:       4c 3b a4 24 b8 00 00    cmp    r12,QWORD PTR [rsp+0xb8]
    4e10:       00
    4e11:       75 1d                   jne    4e30 <main::h3a7d143d57a98e1aeaa+0x180>
    4e13:       48 8d bc 24 b0 00 00    lea    rdi,[rsp+0xb0]
    4e1a:       00
    4e1b:       e8 20 02 00 00          call   5040 <raw_vec::RawVec$LT$T$GT$::double::h4876174689768493710>
    4e20:       4c 8b bc 24 b0 00 00    mov    r15,QWORD PTR [rsp+0xb0]
    4e27:       00
    4e28:       4c 8b a4 24 c0 00 00    mov    r12,QWORD PTR [rsp+0xc0]
    4e2f:       00
    4e30:       4f 89 34 e7             mov    QWORD PTR [r15+r12*8],r14
    4e34:       4c 8b a4 24 c0 00 00    mov    r12,QWORD PTR [rsp+0xc0]
    4e3b:       00
    4e3c:       49 ff c4                inc    r12
    4e3f:       4c 89 a4 24 c0 00 00    mov    QWORD PTR [rsp+0xc0],r12
    4e46:       00
    4e47:       48 ff c5                inc    rbp
    4e4a:       48 81 fd 00 00 01 00    cmp    rbp,0x10000
    4e51:       0f 82 39 ff ff ff       jb     4d90 <main::h3a7d143d57a98e1aeaa+0xe0>
    4e57:       48 8b 8c 24 b0 00 00    mov    rcx,QWORD PTR [rsp+0xb0]
    4e5e:       00
    4e5f:       48 89 4c 24 08          mov    QWORD PTR [rsp+0x8],rcx
    4e64:       4c 89 64 24 10          mov    QWORD PTR [rsp+0x10],r12
    4e69:       4e 8d 34 e1             lea    r14,[rcx+r12*8]
    4e6d:       bb 01 00 00 00          mov    ebx,0x1
    4e72:       41 bd 00 00 01 00       mov    r13d,0x10000
    4e78:       4c 8d 64 24 38          lea    r12,[rsp+0x38]
    4e7d:       0f 1f 00                nop    DWORD PTR [rax]
    4e80:       48 8d 43 01             lea    rax,[rbx+0x1]
    4e84:       48 89 44 24 18          mov    QWORD PTR [rsp+0x18],rax
    4e89:       31 f6                   xor    esi,esi
    4e8b:       ba 00 00 01 00          mov    edx,0x10000
    4e90:       48 8d bc 24 c8 00 00    lea    rdi,[rsp+0xc8]
    4e97:       00
    4e98:       e8 d3 f8 ff ff          call   4770 <memset@plt>
    4e9d:       48 83 7c 24 10 00       cmp    QWORD PTR [rsp+0x10],0x0
    4ea3:       4c 89 ed                mov    rbp,r13
    4ea6:       41 bf 00 00 00 00       mov    r15d,0x0
    4eac:       0f 84 7e 00 00 00       je     4f30 <main::h3a7d143d57a98e1aeaa+0x280>
    4eb2:       48 c1 e3 10             shl    rbx,0x10
    4eb6:       48 8b 4c 24 08          mov    rcx,QWORD PTR [rsp+0x8]
    4ebb:       0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]
    4ec0:       48 8b 31                mov    rsi,QWORD PTR [rcx]
    4ec3:       48 85 f6                test   rsi,rsi
    4ec6:       74 43                   je     4f0b <main::h3a7d143d57a98e1aeaa+0x25b>
    4ec8:       48 83 c1 08             add    rcx,0x8
    4ecc:       31 d2                   xor    edx,edx
    4ece:       48 89 d8                mov    rax,rbx
    4ed1:       48 f7 f6                div    rsi
    4ed4:       48 89 f0                mov    rax,rsi
    4ed7:       48 29 d0                sub    rax,rdx
    4eda:       31 d2                   xor    edx,edx
    4edc:       48 f7 f6                div    rsi
    4edf:       48 81 fa ff ff 00 00    cmp    rdx,0xffff
    4ee6:       77 1c                   ja     4f04 <main::h3a7d143d57a98e1aeaa+0x254>
    4ee8:       0f 1f 84 00 00 00 00    nop    DWORD PTR [rax+rax*1+0x0]
    4eef:       00
    4ef0:       c6 84 14 c8 00 00 00    mov    BYTE PTR [rsp+rdx*1+0xc8],0x1
    4ef7:       01
    4ef8:       48 01 f2                add    rdx,rsi
    4efb:       48 81 fa 00 00 01 00    cmp    rdx,0x10000
    4f02:       72 ec                   jb     4ef0 <main::h3a7d143d57a98e1aeaa+0x240>
    4f04:       4c 39 f1                cmp    rcx,r14
    4f07:       75 b7                   jne    4ec0 <main::h3a7d143d57a98e1aeaa+0x210>
    4f09:       eb 15                   jmp    4f20 <main::h3a7d143d57a98e1aeaa+0x270>
    4f0b:       48 8d 3d 5e 83 24 00    lea    rdi,[rip+0x24835e]        # 24d270 <panic_loc4648>
    4f12:       e8 89 65 03 00          call   3b4a0 <panicking::panic::h4265c0105caa1121SaM>
    4f17:       eb af                   jmp    4ec8 <main::h3a7d143d57a98e1aeaa+0x218>
    4f19:       0f 1f 80 00 00 00 00    nop    DWORD PTR [rax+0x0]
    4f20:       4c 89 ed                mov    rbp,r13
    4f23:       45 31 ff                xor    r15d,r15d
    4f26:       66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
    4f2d:       00 00 00
    4f30:       42 80 bc 3c c8 00 00    cmp    BYTE PTR [rsp+r15*1+0xc8],0x0
    4f37:       00 00
    4f39:       75 56                   jne    4f91 <main::h3a7d143d57a98e1aeaa+0x2e1>
    4f3b:       48 89 6c 24 20          mov    QWORD PTR [rsp+0x20],rbp
    4f40:       48 8d 05 69 70 03 00    lea    rax,[rip+0x37069]        # 3bfb0 <fmt::num::usize.fmt..Display::fmt::h841af16830bb5f60kgW>
    4f47:       48 89 44 24 30          mov    QWORD PTR [rsp+0x30],rax
    4f4c:       48 8d 44 24 20          lea    rax,[rsp+0x20]
    4f51:       48 89 44 24 28          mov    QWORD PTR [rsp+0x28],rax
    4f56:       48 8d 05 3b 83 24 00    lea    rax,[rip+0x24833b]        # 24d298 <ref4653>
    4f5d:       48 89 44 24 38          mov    QWORD PTR [rsp+0x38],rax
    4f62:       48 c7 44 24 40 02 00    mov    QWORD PTR [rsp+0x40],0x2
    4f69:       00 00
    4f6b:       48 8d 44 24 48          lea    rax,[rsp+0x48]
    4f70:       0f 57 c0                xorps  xmm0,xmm0
    4f73:       0f 11 00                movups XMMWORD PTR [rax],xmm0
    4f76:       48 8d 44 24 28          lea    rax,[rsp+0x28]
    4f7b:       48 89 44 24 58          mov    QWORD PTR [rsp+0x58],rax
    4f80:       48 c7 44 24 60 01 00    mov    QWORD PTR [rsp+0x60],0x1
    4f87:       00 00
    4f89:       4c 89 e7                mov    rdi,r12
    4f8c:       e8 cf 2d 00 00          call   7d60 <io::stdio::_print::h27ae99cc97e67314Erh>
    4f91:       49 ff c7                inc    r15
    4f94:       48 ff c5                inc    rbp
    4f97:       49 81 ff 00 00 01 00    cmp    r15,0x10000
    4f9e:       72 90                   jb     4f30 <main::h3a7d143d57a98e1aeaa+0x280>
    4fa0:       49 81 c5 00 00 01 00    add    r13,0x10000
    4fa7:       48 8b 44 24 18          mov    rax,QWORD PTR [rsp+0x18]
    4fac:       48 3d ff ff 00 00       cmp    rax,0xffff
    4fb2:       48 89 c3                mov    rbx,rax
    4fb5:       0f 86 c5 fe ff ff       jbe    4e80 <main::h3a7d143d57a98e1aeaa+0x1d0>
    4fbb:       48 8b b4 24 b8 00 00    mov    rsi,QWORD PTR [rsp+0xb8]
    4fc2:       00
    4fc3:       48 85 f6                test   rsi,rsi
    4fc6:       74 22                   je     4fea <main::h3a7d143d57a98e1aeaa+0x33a>
    4fc8:       48 b8 1d 1d 1d 1d 1d    movabs rax,0x1d1d1d1d1d1d1d1d
    4fcf:       1d 1d 1d
    4fd2:       48 39 c6                cmp    rsi,rax
    4fd5:       74 13                   je     4fea <main::h3a7d143d57a98e1aeaa+0x33a>
    4fd7:       48 c1 e6 03             shl    rsi,0x3
    4fdb:       ba 08 00 00 00          mov    edx,0x8
    4fe0:       48 8b 7c 24 08          mov    rdi,QWORD PTR [rsp+0x8]
    4fe5:       e8 26 12 01 00          call   16210 <__rust_deallocate>
    4fea:       48 81 c4 c8 00 01 00    add    rsp,0x100c8
    4ff1:       5b                      pop    rbx
    4ff2:       41 5c                   pop    r12
    4ff4:       41 5d                   pop    r13
    4ff6:       41 5e                   pop    r14
    4ff8:       41 5f                   pop    r15
    4ffa:       5d                      pop    rbp
    4ffb:       c3                      ret
    4ffc:       48 89 c3                mov    rbx,rax
    4fff:       48 8b b4 24 b8 00 00    mov    rsi,QWORD PTR [rsp+0xb8]
    5006:       00
    5007:       48 85 f6                test   rsi,rsi
    500a:       74 25                   je     5031 <main::h3a7d143d57a98e1aeaa+0x381>
    500c:       48 b8 1d 1d 1d 1d 1d    movabs rax,0x1d1d1d1d1d1d1d1d
    5013:       1d 1d 1d
    5016:       48 39 c6                cmp    rsi,rax
    5019:       74 16                   je     5031 <main::h3a7d143d57a98e1aeaa+0x381>
    501b:       48 c1 e6 03             shl    rsi,0x3
    501f:       48 8b bc 24 b0 00 00    mov    rdi,QWORD PTR [rsp+0xb0]
    5026:       00
    5027:       ba 08 00 00 00          mov    edx,0x8
    502c:       e8 df 11 01 00          call   16210 <__rust_deallocate>
    5031:       48 89 df                mov    rdi,rbx
    5034:       e8 e7 fa ff ff          call   4b20 <_Unwind_Resume@plt>
    5039:       eb c1                   jmp    4ffc <main::h3a7d143d57a98e1aeaa+0x34c>
    503b:       eb bf                   jmp    4ffc <main::h3a7d143d57a98e1aeaa+0x34c>
    503d:       0f 1f 00                nop    DWORD PTR [rax]

関連リンク

Raspberry Pi 3にChinachuをインストールするときのメモ

Raspberry Pi 3にChinachuをインストールする際、公式のインストールガイドのままではうまくインストールできないので、対処法のメモ。

ffmpegを自前でビルドする

commit 48afd7でスタティックビルド版のffmpegをインストールするようになっているが、スタティックビルド版にはarmhf版がない。 そこで、インストール時は自前ビルドを行う古いバージョンのスクリプトを用いるようにする。

$ wget https://github.com/kanreisa/Chinachu/raw/b34cbbf1eddf60be678ec3e5d441e7c3cb6818bc/chinachu -O chinachu_old
$ chmod +x chinachu_old

コンパイルオプションを修正する

Raspberry Pi 3のCPUであるCortex-A53の場合、gcc-march=nativeオプションをつけるとクラッシュしてしまうバグが存在する。 また、nodeのビルドはコンパイルオプションがARMv7以下でないと失敗する。 そこで、-march=nativeの代わりにRaspberry Pi 2と同等のコンパイルオプションを使うように修正する。

--- chinachu_old       2016-05-05 01:23:16.456616228 +0900
+++ chinachu_old       2016-05-05 01:23:22.606583914 +0900
@@ -77,8 +77,8 @@
   ensure_dir "$USR_DIR/src"
   ensure_dir "$USR_DIR/bin"

-  export CFLAGS="-O2 -w -pipe -march=native"
-  export CXXFLAGS="-O2 -w -pipe -march=native"
+  export CFLAGS="-O2 -w -pipe -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard"
+  export CXXFLAGS="-O2 -w -pipe -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard"
   export MAKEFLAGS="-j $((`grep processor /proc/cpuinfo | wc -l` + 1)) -l 3"

   echo "Chinachu Installer Menu:"

上記の修正を加えたインストールスクリプトを実行することで、nodeおよびffmpegのビルドが正常に完了するようになる。

$ ./chinachu_old installer

C#+WPFでGUIアプリケーションを作ってみる

「JavaFX+FXMLでGUIアプリケーションを作ってみる」では、JavaFX+FXMLを使ってJavaランタイム(JRE)が入っている環境向けのGUIアプリケーションを作った。 ここでは、C#+WPFを使い、.NET Frameworkが入っている環境向けのGUIアプリケーションを作ってみる。

環境

Windows 8.1 Pro 64 bit版

>systeminfo
OS 名:                  Microsoft Windows 8.1 Pro
OS バージョン:          6.3.9600 N/A ビルド 9600
OS ビルドの種類:        Multiprocessor Free
システムの種類:         x64-based PC
プロセッサ:             1 プロセッサインストール済みです。
                        [01]: Intel64 Family 6 Model 69 Stepping 1 GenuineIntel ~1596 Mhz

Visual Studio Community 2015のインストール

まず、C# 6.0を使うために、Visual Studio Community 2015をインストールする。

HDD容量を節約するため、ここではインストール時のオプションとして「Custom」を選択し、C++開発に必要となる以下のコンポーネントのみをインストールした。

なお、C#を使うだけであればこれらも不要である。

インストールが終わったらOSを再起動し、アプリケーションメニューからVisual Studioを起動する。 初期設定はデフォルトで進めればよい。

GUIアプリケーションを作ってみる

「Java+SwingでGUIアプリケーションを作ってみる」と同様に、ドラッグアンドドロップされたファイルのSHA-1ハッシュ値をテーブルに表示するアプリケーションを書いてみる。

「File」→「New」→「Project」を開き、「Templates」→「Visual C#」→「Windows」から「WPF Application」を選択する。 さらに、名前を「SHA1CalculatorWPF」としてOKを押し、プロジェクトを作成する。

まず、MainWindow.xamlについて、ToolBoxからDataGridを選択し配置する。 また、WindowのTitle属性を「MainWindow」から「SHA-1 Calculator WPF」に書き換える。 さらに他のコードを書きながら編集していくと、最終的には次のようなコードとなる。

<Window x:Class="SHA1CalculatorWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SHA1CalculatorWPF"
        mc:Ignorable="d"
        Title="SHA-1 Calculator WPF" Height="350" Width="640">
    <Grid AllowDrop="True" DragOver="Grid_DragOver" Drop="Grid_Drop">
        <DataGrid x:Name="dataGrid" AutoGenerateColumns="False" CanUserResizeRows="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="File Path" Binding="{Binding Path}" Width="*"/>
                <DataGridTextColumn Header="sha1sum" Binding="{Binding Sha1sum}" Width="*"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

GridのDragOver、Drop属性が、次のコードで定義しているハンドラ関数に対応する。 また、DataGridTextColumnのBinding属性で指定した変数が、FileInfoクラスのメンバ変数に対応する。

MainWindow.xaml.csを開き、動作を記述するコードを書くと次のようになる。

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows;

namespace SHA1CalculatorWPF
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        ObservableCollection<FileInfo> fileList;

        public class FileInfo : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }

            public string Path { get; set; }

            private string _sha1sum;
            public string Sha1sum
            {
                get { return _sha1sum; }
                set
                {
                    if (value != _sha1sum)
                    {
                        _sha1sum = value;
                        NotifyPropertyChanged();
                    }
                }
            }
        }

        public MainWindow()
        {
            InitializeComponent();

            fileList = new ObservableCollection<FileInfo>();
            dataGrid.ItemsSource = fileList;
        }

        private void Grid_DragOver(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effects = DragDropEffects.Copy;
            }
            else
            {
                e.Effects = DragDropEffects.None;
            }
            e.Handled = false;
        }

        private void Grid_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                var paths = (string[])e.Data.GetData(DataFormats.FileDrop);
                foreach (var path in paths)
                {
                    var fileinfo = new FileInfo { Path = path, Sha1sum = "" };
                    fileList.Add(fileinfo);
                    var worker = new BackgroundWorker();
                    worker.DoWork += worker_DoWork;
                    worker.RunWorkerAsync(fileinfo);
                }
            }
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            // update digest with each 8MB chunk
            var fileinfo = (FileInfo)e.Argument;
            var fs = new FileStream(fileinfo.Path, FileMode.Open, FileAccess.Read);
            var sha1 = new System.Security.Cryptography.SHA1Managed();
            var buf = new byte[8 * 1024 * 1024];
            int n = fs.Read(buf, 0, buf.Length);
            while (fs.Position < fs.Length)
            {
                sha1.TransformBlock(buf, 0, n, buf, 0);
                fileinfo.Sha1sum = string.Format("Calculating {0}%...", 100L * fs.Position / fs.Length);
                n = fs.Read(buf, 0, buf.Length);
            }
            sha1.TransformFinalBlock(buf, 0, n);
            fileinfo.Sha1sum = BitConverter.ToString(sha1.Hash).Replace("-", "").ToLower();
        }
    }
}

上のコードでは、ObservableCollectionをDataGridのItemsSourceにセットすることで、データバインディングを行っている。 ただし、FileInfoクラスのメンバ変数の変更までは即座にビューに反映されないため、FileInfoクラスにもINotifyPropertyChangedインタフェースを実装する必要がある。 そして、プロパティのsetterの中でPropertyChangedEventHandlerを呼ぶことにより、更新をビューに通知する。 また、バッググラウンドスレッドを生成するには、BackgroundWorkerを使う。 SHA-1ハッシュの計算には.NET基盤(CLR)上で計算するSHA1ManagedクラスとWindows APIを利用するSHA1CryptoServiceProviderSHA1Cngクラスが使えるが、基本的にはSHA1Managedを使えばよい(参考)。

コードを保存した後「Start」を押して実行し、適当にファイルをドラッグアンドドロップした後のスクリーンショットを次に示す。

f:id:inaz2:20160502010405p:plain

進捗を表す文字列がビューにリアルタイムで表示され、ハッシュ値が計算できていることが確認できる。

実行可能なexeファイルを作成する

ビルド設定を「Debug」から「Release」に変えてビルドすることで、プロジェクトフォルダのSHA1CalculatorWPF\bin\Release以下にデバッグ情報を含まないexeファイルが生成される。 また、メニューの「Build」→「Publish SHA1CalculatorWPF」を選ぶことで、ClickOnceインストーラを作成することもできる。

生成されたexeファイルを実行すると、上と同様のウィンドウが表示されることが確認できる。

関連リンク

objdumpのdiffをいい感じに取る方法のメモ

たとえば、次のような二つのC言語コードを考える。

/* test1.c */
#include <stdio.h>

double divide(long x, long y)
{
    return x/(double)y;
}

int main()
{
    divide(1, 2);
    divide(1, 0);
    return 0;
}
/* test2.c */
#include <stdio.h>
#include <stdlib.h>

double divide(long x, long y)
{
    if (!y) {
        exit(1);
    }
    return x/(double)y;
}

int main()
{
    divide(1, 2);
    divide(1, 0);
    return 0;
}

二つ目のコードは、被除数が0かどうかのチェックを加えたものである。 これらをそれぞれコンパイルし、objdumpで逆アセンブルしたもののdiffを取ると次のようになる。

$ make test1 test2
cc     test1.c   -o test1
cc     test2.c   -o test2

$ diff -u <(objdump -d test1) <(objdump -d test2)
--- /dev/fd/63  2016-04-30 07:28:59.852032082 +0900
+++ /dev/fd/62  2016-04-30 07:28:59.852032082 +0900
@@ -1,193 +1,202 @@

-test1:     file format elf64-x86-64
+test2:     file format elf64-x86-64


 Disassembly of section .init:

-00000000004003a8 <_init>:
-  4003a8:      48 83 ec 08             sub    rsp,0x8
-  4003ac:      48 8b 05 45 0c 20 00    mov    rax,QWORD PTR [rip+0x200c45]        # 600ff8 <_DYNAMIC+0x1d0>
-  4003b3:      48 85 c0                test   rax,rax
-  4003b6:      74 05                   je     4003bd <_init+0x15>
-  4003b8:      e8 33 00 00 00          call   4003f0 <__gmon_start__@plt>
-  4003bd:      48 83 c4 08             add    rsp,0x8
-  4003c1:      c3                      ret
+00000000004003e0 <_init>:
+  4003e0:      48 83 ec 08             sub    rsp,0x8
+  4003e4:      48 8b 05 0d 0c 20 00    mov    rax,QWORD PTR [rip+0x200c0d]        # 600ff8 <_DYNAMIC+0x1d0>
+  4003eb:      48 85 c0                test   rax,rax
+  4003ee:      74 05                   je     4003f5 <_init+0x15>
+  4003f0:      e8 2b 00 00 00          call   400420 <__gmon_start__@plt>
+  4003f5:      48 83 c4 08             add    rsp,0x8
+  4003f9:      c3                      ret

 Disassembly of section .plt:

-00000000004003d0 <__libc_start_main@plt-0x10>:
-  4003d0:      ff 35 32 0c 20 00       push   QWORD PTR [rip+0x200c32]        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
-  4003d6:      ff 25 34 0c 20 00       jmp    QWORD PTR [rip+0x200c34]        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
-  4003dc:      0f 1f 40 00             nop    DWORD PTR [rax+0x0]
-
(snip)

主にアドレス部分のずれにより、まったくdiffが取れていないことがわかる。

このような場合、次のようなコマンドを打つとよい。

$ diff -u1 -F '>:$' -I '[0-9a-f]\{6,\}' <(objdump -d test1 | cut -f2-) <(objdump -d test2 | cut -f2-)
--- /dev/fd/63  2016-04-30 07:40:28.072016196 +0900
+++ /dev/fd/62  2016-04-30 07:40:28.072016196 +0900
@@ -1,3 +1,3 @@

-test1:     file format elf64-x86-64
+test2:     file format elf64-x86-64

@@ -30,3 +30,8 @@ 00000000004003f0 <__gmon_start__@plt>:
 68 01 00 00 00         push   0x1
-e9 d0 ff ff ff         jmp    4003d0 <_init+0x28>
+e9 d0 ff ff ff         jmp    400400 <_init+0x20>
+
+0000000000400430 <exit@plt>:
+ff 25 f2 0b 20 00      jmp    QWORD PTR [rip+0x200bf2]        # 601028 <_GLOBAL_OFFSET_TABLE_+0x28>
+68 02 00 00 00         push   0x2
+e9 c0 ff ff ff         jmp    400400 <_init+0x20>

@@ -118,4 +123,9 @@ 00000000004004ed <divide>:
 48 89 e5               mov    rbp,rsp
+48 83 ec 20            sub    rsp,0x20
 48 89 7d f8            mov    QWORD PTR [rbp-0x8],rdi
 48 89 75 f0            mov    QWORD PTR [rbp-0x10],rsi
+48 83 7d f0 00         cmp    QWORD PTR [rbp-0x10],0x0
+75 0a                  jne    40054e <divide+0x21>
+bf 01 00 00 00         mov    edi,0x1
+e8 e2 fe ff ff         call   400430 <exit@plt>
 f2 48 0f 2a 45 f8      cvtsi2sd xmm0,QWORD PTR [rbp-0x8]
@@ -127,3 +137,3 @@ 00000000004004ed <divide>:
 f2 0f 10 45 e8         movsd  xmm0,QWORD PTR [rbp-0x18]
-5d                     pop    rbp
+c9                     leave
 c3                     ret
@@ -142,4 +152,3 @@ 000000000040051d <main>:
 c3                     ret
-66 2e 0f 1f 84 00 00   nop    WORD PTR cs:[rax+rax*1+0x0]
-00 00 00
+0f 1f 44 00 00         nop    DWORD PTR [rax+rax*1+0x0]

-u1は差分の前後1行のみを表示させるオプション、-F正規表現にマッチする行をセクション見出しとして扱うオプション、-I正規表現にマッチする行のみの差分を除外するオプションである。