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

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

Clojureを使ってみる

たまたまClojureを触ってみて、なんだか良さそうだと感じたのでいろいろ書き散らしている。
環境構築が比較的容易で、WEBアプリが作りやすそうなのがよかった。あとScalaほど四角四面ではなく、Groovyほど壊れにくい*1

環境構築

yoppi.hatenablog.com

まずこれでMavenと連携させてみる

Leiningen

そしてLeiningenを入れる
Windowsの場合、Msys2上でUNIX用のスクリプトを動かしたほうが早い

> wget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein -O /usr/bin/lein
> lein self-install
> lein --version
Leiningen 2.7.1 on Java 1.8.0_112 Java HotSpot(TM) 64-Bit Server VM

Maven

プロジェクトを作ってMaven

$ lein new wiki

project.clj ができるので、そこからpomを作る

$ lein pom

leinが出力するpom.xmlは、全部project.cljが元である。Mavenに慣れているならパズルゲームみたいな感じで設定出来ると思う。

Hello, World!!

ここからHello, Worldまではこのサイトがわかりやすい

qiita.com

core.cljを書き換えて・・・最終的にこうなった

(ns wiki.core
  (:gen-class main true))

(defn -main
  "I don't do a whole lot."
  [& args]
  (println "Hello, World!"))

Emacs

適当にこんな感じ

;; Clojure
(unless (package-installed-p 'clojure-mode)
  (package-refresh-contents) (package-install 'clojure-mode))
(require 'clojure-mode)
(add-to-list 'auto-mode-alist '("\\.clj$" . clojure-mode))

EmacsでモダンClojure開発環境構築 - Qiita
新: Emacs を使うモダンな Clojure 開発環境 - Qiita

cider-modeはmsys2では動かないかもしれない。

コレクション操作

Ruby

見慣れた形、データが先で関数で回す
# listの中身をトレース
[1, 2, 3].each do |n|
    puts n
end

# mapの中身をトレース
{ 1 => "a", 2 => "b", 3 => "c" }.each do |k, v|
    puts "#{k}, #{v}"
end

Clojure

Lispなのでデータが後で関数が先

mapについては doseq, reduce-kv 2つの関数を見つけた

; listの中身をトレース
(map #(println %) [1 2 3])
(map #(prn %) [1 2 3])

; mapの中身をトレース
(doseq [[k v] {1 "a" 2 "b" 3 "c"}] (prn k v))
(reduce-kv #(println %2 %3) 0 {1 "a" 2 "b" 3 "c"})

マクロとかLispっぽさ、関数型言語っぽい書き方もできたりするのだろうか。
チュートリアルを見ているとClojureは結構実用的に感じた。

Clojure の日本語ガイド — Clojure の日本語ガイド

プログラミングClojure 第2版

プログラミングClojure 第2版

*1:偏見…?

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)