なんとな~くしあわせ?の日記

「そしてそれゆえ、知識そのものが力である」 (Nam et ipsa scientia potestas est.) 〜 フランシス・ベーコン

x86 汎用命令 - ModR/M の解説

ModR/Mについては前もちょっと記事を書いたけど、まだちょっと中途半端だったのでもう一度まとめます。

nantonaku-shiawase.hatenablog.com

ModR/Mの実際の例

例えば以下のような命令がある、 /r の意図がみなさんわからないのではないでしょうか?

; IMUL r32, imm32
0x69 /r iw

また、次のような命令、 /7 の意図がみなさんわからないのではないでしょうか?

; CMP r/m8, imm8
0x80 /7 ib

ModR/Mの構造

全体の概要についてはこのページをみたほうがよい

また、このページも役立つ

ModR/Mバイトの構造
  • ModR/Mバイトは画像のような構造になっており、それを指定された場合アセンブラは「mod/reg/rm」の3つの要素を1byteで出力する

https://freestylewiki.xyz/fswiki/wiki.cgi?page=%E3%82%A2%E3%82%BB%E3%83%B3%E3%83%96%E3%83%A9%28ModR%2FM%29&file=modrm%2Epng&action=ATTACH

  • でも実際はregとr/mはそれぞれレジスタを指すので、ほぼ同じようなものだと思っていい
'''/r'''および'''/7'''の意味

解説を Assembly Programming on x86-64 Linux (06) から引用する

この記事で注目している項目を赤字で表現。

記法 解説
/0 - /7 ModR/M バイト の reg フィールドの 0 から 7 の数字はオペコードの拡張用に使われる。r/m フィールドだけをオペランドに使用する。
/r 命令には ModR/M バイトが続き、レジスタオペランドと r/m オペランドの両方を使う。
cb、cw、cd、cp, co, ct オペコードの後に 1 バイト(cb)、2 バイト(cw)、4 バイト(cd)、6 バイト(cp)、 8 バイト(co)または 10 バイト(ct)が続く。
ib, iw, id, io オペコード、ModM/R バイト、または SIB の後に続く 1 バイト(ib)、2 バイト(iw)、4 バイト(id)または 8 バイト(io)の定数(即値)。
+rb, +rw, +rd, +ro + の左側のオペコードに加算される 0 から 7 までのレジスタコード。 結果として 1 バイトのオペコードとなる。
regとr/mで使われるレジスタコード
レジスタコード レジスタ
000 al ax eax
001 cl cx ecx
010 dl dx edx
011 bl bx ebx
100 ah sp esp
101 ch bp ebp
110 dh si esi
111 bh di edi

mod

reg(/0 - /7指定の場合)

  • regは、/0 - /7を指定された場合はそれをそのまま使う

もちろんこれは10進数表記なので、2進数に直すと以下のようになる。ModR/Mバイトのregフィールドはこれで埋まるわけだ。

/0 - /7 2進数表記
/0 000
/1 001
/2 010
/3 011
/4 100
/5 101
/6 110
/7 111

reg(/0 - /7指定の場合)の実例

; 0x80 /7 ib
CMP r/m8, imm8
; 例
CMP CL,18
; オペコードは0x80で確定
; ---------------------
; ModR/Mの値は
; [mod] 11
; [reg] 111
; [r/m] 001
; => "11111001" 
; => 0xf9
; ---------------------
; 18は16進数で0x12
; ---------------------
; よって、以下がアセンブルされると
CMP CL,18
; 以下のバイナリが出力される
0x80, 0xf9, 0x12

reg('''/r'''指定の場合)

つまり、mod2bitに続いて、regr/mが3bitずつ続くことになる

reg(/r指定の場合)の実例

; 0x69 /r iw
IMUL r32, imm32
; 例
IMUL ECX,4608
; オペコードは0x69で確定
; ---------------------
; ModR/Mの値は
; [mod] 11
; [reg] 001
; [r/m] 001
; => "11001001" 
; => 0xc9
; ---------------------
; 4608は16進数で0x1200
; リトルエンディアンのため、 0x00, 0x12と並ぶ
; ---------------------
; よって、以下がアセンブルされると
IMUL ECX,4608
; 以下のバイナリが出力される
0x69, 0xc9, 0x00, 0x12

/r指定の場合のレジスタの細かい指定

さて、実はここまでregとr/mのどちらがどちらのレジスタを指定しているのか気になった人がいるかもしれない。その指摘はめっちゃ正しい。

ここのサイトに答えが書いてある。

The d bit in the opcode determines which operand is the source, and which is the destination:

d=0: MOD R/M <- REG, REG is the source
d=1: REG <- MOD R/M, REG is the destination

"d"bitというのは、1byte(8bit)のデータを先頭から数えて4番目のbitである。*1
つまり、"d"bitが0か1かによってmodとr/mの3bitをそれぞれ入れ替えなければいけない。

C++の疑似コード、std::bitsetを使うとやりやすい

uint8_t op = 0x8e;
std::bitset<8> bsl(op); // オペコード

if (bsl[3]) { // d=0 or 1
  // d=1: REG <- MOD R/M, REG is the destination
} else {
  // d=0: MOD R/M <- REG, REG is the source
}

はじめて読む486、ModRMとかに関してはほとんど役に立たず…

はじめて読む486―32ビットコンピュータをやさしく語る

はじめて読む486―32ビットコンピュータをやさしく語る

*1:わかるか…!こんな細かい仕様…!

Let's Encryptを手動更新

blog.apar.jp

だいたいここの指示にしたがえばよし

こんなエラーが出た。

Cleaning up challenges
Attempting to renew cert from /etc/letsencrypt/renewal/freestylewiki.xyz.conf produced an unexpected error: At least one of the required ports is already taken.. Skipping.

httpdを一回停止させればOK

# systemctl stop httpd

成功時のログ

* Pythonスクリプトがいろいろやってる(秘密鍵更新+CSR作成+証明書作成(中間証明書も))

[root@freestylewiki letsencrypt]# ./certbot-auto renew --force-renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/freestylewiki.xyz.conf
-------------------------------------------------------------------------------
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
Renewing an existing certificate
Performing the following challenges:
tls-sni-01 challenge for freestylewiki.xyz
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0001_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0001_csr-certbot.pem

-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/freestylewiki.xyz/fullchain.pem
-------------------------------------------------------------------------------

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/freestylewiki.xyz/fullchain.pem (success)

Heroku + Plack + plenvを試す

ある目的のためにPlackをHerokuに上げたいと思っていた。で、試したので手順を書いておく。

plack-testing

今回試したリポジトリ
github.com

手順

初期設定

plenv

Rubyで言うところのrbenv、結構古いPerlじゃないと依存関係がぶっ壊れる

$ git clone git://github.com/tokuhirom/plenv.git ~/.plenv
$ git clone git://github.com/tokuhirom/Perl-Build.git ~/.plenv/plugins/perl-build/
$ echo 'export PATH="$HOME/.plenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(plenv init -)"' >> ~/.bash_profile
$ exec $SHELL -l
$ plenv install 5.16.3

cpanm

  • cpan minusという意味らしい、cpan plusというcpanの拡張版の機能軽量化版だと思われる
  • Rubyで言うところのGemfileである
  • cpanfileに依存関係を記述する、そんでcpanmを実行
$ mkdir bin
$ cd bin
$ curl -LOk http://xrl.us/cpanm
$ chmod +x cpanm
インストールとアプリケーションサーバの起動
$ bin/cpanm -L . --installdeps .
$ ./start.sh
Heroku / Heroku buildpack: Perl
  • ここ必見、HerokuにPerlのアプリケーションを上げる時、これが使える

qiita.com

  • heroku createがHeroku上にアプリを登録する
  • git push heroku masterは今のコードをHerokuにデプロイする、まあなんてクリアなコードでデプロイ出来るんでしょう
$ heroku create --buildpack http://github.com/pnu/heroku-buildpack-perl.git
$ git push heroku master
Counting objects: 22, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (20/20), done.
Writing objects: 100% (22/22), 3.04 KiB | 0 bytes/s, done.
Total 22 (delta 7), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote: 
remote: -----> Perl/PSGI app detected
remote: -----> Vendoring https://heroku-buildpack-perl.s3.amazonaws.com/cedar-14/perl-5.16.3.tgz
remote: -----> Vendoring https://heroku-buildpack-perl.s3.amazonaws.com/cedar-14/perl-5.16.3-extras.tgz
remote: -----> Current perl version is 5.16.3
remote: -----> Random RELEASE_UUID=794f391bff3b74b4946ff4ecebd3aad70b87ea46915f22c782a1b6762b0d08ee
remote: -----> Bootstrapping cpanm and local::lib
remote:        Successfully installed App-cpanminus-1.7042 (upgraded from 1.7014)
remote:        Successfully installed local-lib-2.000019 (upgraded from 2.000014)
remote:        2 distributions installed
remote: -----> Installing dependencies (cpanm)
remote:        Successfully installed JavaScript-Value-Escape-0.07
remote:        Successfully installed Plack-Middleware-ConsoleLogger-0.05
remote:        Successfully installed CGI-4.33 (upgraded from 3.59)
remote:        Successfully installed CGI-Emulate-PSGI-0.22
remote:        Successfully installed CGI-Compile-0.21
remote:        Successfully installed Plack-Middleware-Auth-Digest-0.05
remote:        Successfully installed Plack-Middleware-Deflater-0.12
remote:        Successfully installed AnyEvent-HTTP-2.23
remote:        Successfully installed Plack-App-Proxy-0.29
remote:        Successfully installed CGI-PSGI-0.15
remote:        Successfully installed asa-1.03
remote:        Successfully installed IO-Handle-Util-0.01
remote:        Successfully installed Any-Moose-0.26
remote:        Successfully installed FCGI-Client-0.08
remote:        Successfully installed Text-MicroTemplate-0.24
remote:        Successfully installed Plack-Middleware-Debug-0.16
remote:        Successfully installed Test-HexString-0.03
remote:        Successfully installed Net-FastCGI-0.14
remote:        Successfully installed Canary-Stability-2012
remote:        Successfully installed Coro-6.511
remote:        Successfully installed Net-Server-Coro-1.3
remote:        Successfully installed Corona-0.1004
remote:        Successfully installed Plack-Middleware-Header-0.04
remote:        Successfully installed PSGI-1.102
remote:        Successfully installed Server-Starter-0.32
remote:        Successfully installed IO-Socket-IP-0.38
remote:        Successfully installed Test-TCP-2.17 (upgraded from 2.06)
remote:        Successfully installed Class-Accessor-Lite-0.08
(省略)
remote:        Successfully installed Proc-Wait3-0.05
remote:        Successfully installed IPC-Signal-1.00
remote:        Successfully installed Signal-Mask-0.008
remote:        Successfully installed Parallel-Prefork-0.18
remote:        Successfully installed Starlet-0.30
remote:        Successfully installed Cookie-Baker-0.07
remote:        Successfully installed Plack-Middleware-Session-0.30
remote:        Successfully installed Task-Plack-0.28
remote:        36 distributions installed
remote: -----> Installing Starman
remote:        Successfully installed Starman-0.4014 (upgraded from 0.4010)
remote:        1 distribution installed
remote: -----> Caching local to /app/tmp/cache/perl/cedar-14/
remote: -----> Discovering process types
remote:        Procfile declares types     -> (none)
remote:        Default types for buildpack -> web
remote: 
remote: -----> Compressing...
remote:        Done: 31M
remote: -----> Launching...
remote:        Released v4
remote:        https://thawing-savannah-27493.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy.... done.
To https://git.heroku.com/thawing-savannah-27493.git