Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
RG-Arch 輪講資料: Binary Hacks Rebooted 数値演算など
Search
kota-yata
October 20, 2025
Programming
0
4
RG-Arch 輪講資料: Binary Hacks Rebooted 数値演算など
kota-yata
October 20, 2025
Tweet
Share
More Decks by kota-yata
See All by kota-yata
結局QUICで通信は速くなるの?
kota_yata
10
7.7k
RG-Arch輪考資料: QUIC is not Quick Enough over Fast Internet
kota_yata
0
110
RG-Arch輪考資料: Implementation and Performance Evaluation of the QUIC Protocol in Linux Kernel
kota_yata
0
110
2024年秋 中村研 WIP発表資料
kota_yata
0
60
パタヘネ輪読: 第五章
kota_yata
0
27
パタヘネ輪読: 第一章
kota_yata
0
190
2023年秋 中村研 WIP発表資料
kota_yata
0
110
2023年春 中澤大越研 WIP発表資料
kota_yata
0
61
BigIntの良いとこ悪いとこ
kota_yata
0
100
Other Decks in Programming
See All in Programming
CSC305 Lecture 04
javiergs
PRO
0
270
CSC305 Lecture 06
javiergs
PRO
0
250
登壇は dynamic! な営みである / speech is dynamic
da1chi
0
350
EMこそClaude Codeでコード調査しよう
shibayu36
0
240
『毎日の移動』を支えるGoバックエンド内製開発
yutautsugi
2
260
スマホから Youtube Shortsを見られないようにする
lemolatoon
27
33k
ALL CODE BASE ARE BELONG TO STUDY
uzulla
25
6.5k
Cursorハンズオン実践!
eltociear
2
1.1k
Goで実践するドメイン駆動開発 AIと歩み始めた新規プロダクト開発の現在地
imkaoru
4
870
オープンソースソフトウェアへの解像度🔬
utam0k
16
3.1k
エンジニアインターン「Treasure」とHonoの2年、そして未来へ / Our Journey with Hono Two Years at Treasure and Beyond
carta_engineering
0
360
Le côté obscur des IA génératives
pascallemerrer
0
150
Featured
See All Featured
Why Our Code Smells
bkeepers
PRO
340
57k
4 Signs Your Business is Dying
shpigford
185
22k
Building a Modern Day E-commerce SEO Strategy
aleyda
44
7.8k
Typedesign – Prime Four
hannesfritz
42
2.8k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
31
2.7k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
23
1.5k
Building an army of robots
kneath
306
46k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.2k
The Art of Programming - Codeland 2020
erikaheidi
56
14k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.1k
We Have a Design System, Now What?
morganepeng
53
7.8k
Transcript
Binary Hacks Rebooted イントロ, 数値演算 RG Arch輪講第1回 Presenter: Arch B3
Kota
⽬次 • 1章: イントロダクション ◦ fileコマンドを使わずにファイルの種類を調べる ◦ libcのwrite()を使った標準出⼒ • 7章:
数値表現とデータ処理Hack ◦ 符号付き整数 ◦ エンディアン ◦ 固定⼩数点数 ◦ 可変⻑表現(Zig-zag, UTF-8) ◦ 浮動⼩数点数 ◦ NaN 2
1章-fileコマンドを使わずにファイルの種類を調べる 3 • fileコマンドは特定のファイルの形式,属性を調べるUnixコマンド ◦ 拡張⼦がなくても調べられる • 多くのファイルにはマジックナンバーがあり,最初の数バイトを⾒ると種類が 分かる ◦
e.g. jpgはffd8ffe0,gzipは1f8b ◦ https://en.wikipedia.org/wiki/List_of_file_signatures • コマンド⾃体のhexdumpをするとELFのマジックナンバーが⾒えたりする ◦ Unixにおいて「全てはファイル」 • 古い.tarなどはマジックナンバーを持たず,独⾃の判定ロジックがある
1章-libcのwrite()を使った標準出⼒ 4 • Unix系のOS(Mac OSやLinux OS)においてはファイルディスクリプタの1番 は標準出⼒にアサインされている ◦ ちなみに0番は標準⼊⼒,2番は標準エラー出⼒ ◦
ターミナルが標準出⼒”ファイル”を開いているというイメージ • print(“Hello world!”)は実質標準出⼒ファイルに書き込みしているのと⼀緒 • つまりwrite()でもprintと同じことができる!
7章 数値表現とデータ処理Hack 5
符号なし整数と符号付き整数 • 整数の表現⽅法として符号なし整数と符号付き整数がある(uint, int) • 符号なし整数は2進整数をそのまま表現する ◦ 7 = 00000111(uint8の場合)
• 符号あり整数の場合,表現できる最⼤値の下半分は正の値に使い,上半分は補 数を⽤いて負の値を表現する 6
符号付き整数(int8の例) 7 • 00000000~01111111までは正の値の表現に使う ◦ 符号なし整数と同様の表現⽅法(7=00000111) • 10000000~11111111までは負の値の表現に使う ◦ 「その値の絶対値を⾜したらちょうど桁上がりする値」を負の値とする
◦ 7の2進数表現は00000111なので11111001を⾜せば桁上がりする ◦ これを2の補数表現という • 結果的に8ビットで-128~127を表現できる
補数表現を使うことのメリット 例:-7 -> 0b10000111 とすれば下位7ビットは符号なし整数と同じ.. • 減算を加算で表現できる ◦ 例:7-8を7+(-8)とする ◦
0b00000111 + 0b11111000 = 0b11111111 = -1 ◦ 負の値同⼠の加算もオーバーフローを無視すれば同様に演算が可能 • 0が⼀意に決まる ◦ ⼀番上の例だと+0と-0という⼆つの0が誕⽣する ◦ 0が⼀意に決まる(0b0)補数表現の⽅が楽 8 「MSBを符号ビットとすればそのあとは値をそのまま格納できて直感的では?」
符号拡張 9 • CPUアーキテクチャによっては8ビットや16ビットの変数に対応する幅の命令 がない場合がある ◦ x86-64では切り離せなかった後⽅互換性により8, 16, 32, 64ビット全ての幅に対す
る整数演算命令がある ◦ Arm64など⽐較的新しいアーキテクチャでは32ビットと64ビット幅の整数演算命令 しかない • 演算の前後でレジスタのビット幅に合致するように値を拡張する必要がある ◦ 上位に挿⼊する各桁を符号ビットと同じ値にすれば良い ◦ e.g. 11111001 -> 1111111111111001
エンディアン 10 • 値の上位,下位桁をメモリの上位,下位バイトのどちらと対応させるか ◦ ビッグエンディアン:値の上位がメモリの下位 ◦ リトルエンディアン:値の上位がメモリの上位 例:0xABCDEF01という値を格納する時 メモリ下位
メモリ上位
エンディアン 11 • ネットワークパケットのヘッダー情報はビッグエンディアンと定められている ◦ これはネットワークバイトオーダーと呼ばれる ◦ 各プロトコルで明確に定められているというよりはRFC1700などで慣習として記さ れている •
⼀⽅エンド端末では⼀般にリトルエンディアンが⽤いられる ◦ 幅が異なる変数にキャストした時とかに下位ビットが保持されるメリットがある ◦ ネットワークパケットを作る際はhton関数で変換するのが⼀般的 ◦ x86_64にはbswapやmovbe(拡張命令セット)などの変換命令がある
固定⼩数点数 12 • ⼩数点以下のビット数が固定されている数値型 • 整数部分を8ビット,⼩数部分を8ビットとする符号付き固定⼩数点がある時分 解能は1/256になる(最⼤値は127.996くらい) ◦ 精度がある程度分かっている値を扱う際は固定⼩数点で⼗分なケースがある •
ハードウェア的には整数演算と同じユニットを使えるため,浮動⼩数点と⽐較 して演算の効率が良い
可変⻑表現 13
可変⻑表現 14 • 整数を表現するビット列から冗⻑な部分を取り除いて必要最⼩限のビット数に 圧縮する技術 ◦ WebAssemblyの整数値の格納にはLEB128が使われている ▪ 各バイトについてMSBを継続ビットとし,下位7ビットを実際の数値とする ▪
5 -> 00000101, 300 -> 10101100 00000010 ◦ Protocol BufferではZig-zagエンコーディングが使われている
可変⻑表現-Zig-zagエンコーディング 15 • 2の補数を⽤いる符号付き整数とは対照的に,LSBを符号ビットとする ◦ 0b00000000: 0 ◦ 0b00000001: -1
◦ 0b00000010: 1 ◦ 0b00000011: -2 ◦ 0b00000100: 2 ◦ … ◦ 0b01111111: -127 ◦ 0b11111110: 127 ◦ 0b11111111: -128 例:-1を符号付き整数で表現したい時 • 2の補数表現の場合LEB128で10バイト • Zig-zagを使えばLEB128で1バイト! ⼩さな値は必ず少ないバイト数で表現できる
UTF-8 • LEB128とかなり似ている ◦ 継続ビットを⽤いる点では同じ 16 漢字は⼤体hex4桁なので3バイト必要🥺
おまけ:UTF-16 17 • Unicodeコードポイント U+0000〜U+FFFFはそのまま2バイトで表現 ◦ ⽇本語の常⽤漢字も2バイト! • U+10000〜U+10FFFFは「サロゲート」に分割される ◦
UnicodeにおいてU+D800〜U+DBFFは上位サロゲート,U+DC00〜U+DFFFは下位 サロゲートという予約領域になっている ◦ コードポイント-0x10000をして,結果の上位10ビットを上位,下位10ビットを下 位サロゲートに格納
UTF-16エンコードの例 18 • 0x1F97A - 0x10000 = 0xF97A = 0b00001111100101111010(20ビット)
• 上位10桁と0xD800(上位サロゲートのベース値)と⾜す -> 0xD83E • 残りの桁と0xDC00(下位サロゲートのベース値)と⾜す -> 0xDD7A 🥺はD8 3E DD 7Aの4バイトにエンコードされる 🥺 (U+1F97A)
浮動⼩数点 19
浮動⼩数点数 20 • ⼩数を含む値を仮数部,指数部分に分けて表現する ◦ sが符号ビット,mが仮数部,eが指数部 ◦ b(基数)は⼀般には2(IEEE 754).IEEE754-2008で基数10の仕様が追加された ◦
基数10の例:125.5 = 1.255 * 10^2 ◦ 基数2の例:0.01(10進数で0.25)= 1.0 * 2^-2
浮動⼩数点の正規化 21 • IEEE754では,浮動⼩数点の仮数部は常に”正規化”される ◦ 仮数部のMSBが0でない数になる(e.g. 0.034 -> 3.4, 0.254
-> 2.54) ◦ つまり2進数で表現する時,整数部分は必ず1になるように指数が調整される ▪ e.g. 0.00101 -> 1.01 * 2^-3 ▪ 必ず1なので,実際には仮数部は⼩数点以下から格納される(ケチ表現) • 指数部は”バイアス”をかけて符号なし整数にする ◦ 例えば指数部が8ビットだった場合,実際の値+127をする ◦ 本来-126~127の値が,1~254になる(0は0.0, 255はNaNとinfiniteの表現に使う)
浮動⼩数点のデータ構造 22 • 指数部はバイアスがかかっているので符号なし整数 • 仮数部は⼩数点以下の値を格納
浮動⼩数点の加算 23 • 加算対象の⼆つの値の内指数が⼤きい⽅に合わせる ◦ 1.111 * 2^2 + 1.011
* 2^3の場合指数3に合わせる ◦ 1.111 * 2^2 -> 0.1111 * 2^3 ◦ この段階で⽚⽅の精度が落ちる • 指数を合わせたら仮数部を⾜す ◦ 0.1111 + 1.011 = 10.0101 • 正規化する ◦ 1.00101 * 2^4
丸め 24 • 多くの演算では加算時に桁上がりが発⽣し,値を丸める必要が出てくる • 最もよく使われる丸めかたは”roundTiesToEven” ◦ 最も近い浮動⼩数点数に丸める.ちょうど中間ならLSBが0の⽅に丸める ◦ 例:1.10001₂(=1.53125₁₀)はちょうど1.1000₂
(=1.5₁₀)と1.1001₂ (=1.5625₁₀)の間 ▪ この場合LSBが0の1.1000₂に合わせる • この丸めによってfloat同⼠の等価演算がfalseになったりする ◦ 0.1 + 0.2 !== 0.3 とか
25 NaNの種類
NaNは2種類ある Signaling NaN 26 • 演算の⼊⼒に含まれているとinvalid operation例外を発⽣させる • 未初期化変数を誤って演算に使った際などの検出に使う Quiet
NaN • 主に数値演算の結果として⽣成されるNaN • 演算時のinvalid operationの結果はデフォルトでquite NaN 表現としては,仮数部のMSBが1ならquiet NaN,0ならsignaling NaN…
実はそうとも限らない 27 • IEEE754-1985の時点では⼆種類のNaNの区別はされていなかった • 前述のような区別がなされたのはIEEE754-2008から • MIPSやPA-RISCなど古のアーキテクチャではquite NaNでもMSBが⽴っていな い場合がある
• とはいえ現代的なアーキテクチャであればほとんどIEEE754-2008の仕様通り の実装になっている
Signaling NaNを作ってみよう! 28 • 実際に⼿動でSignaling NaNを作って,演算の⼊⼒に含めてみる • 演算結果がQuite NaNになり,Invalid Operationフラグが⽴つかどうかを確か
めてよう! できたコードがこちら→
学べたこと 29 • 符号付き,符号なしの整数表現と2の補数表現 • 符号拡張,エンディアン,固定⼩数点 • 浮動⼩数点の表現⽅法と演算 • NaNの種類