疲れたので、とりあえずこれをつらつら実行してみる日々。
activatorになって、何がありがたくなったのかよくわからなくなってしまいました。
疲れたので、とりあえずこれをつらつら実行してみる日々。
activatorになって、何がありがたくなったのかよくわからなくなってしまいました。
P.120
SuperHitachiの略
ルネサス製
左から右へ代入している
00fe1400 <_null>: fe1400: 00 0b rts fe1402: 00 09 nop 00fe1404 <_return_zero>: fe1404: 00 0b rts fe1406: e0 00 mov #0,r0
シャープ4とかシャープ2とかが即値
00fe140c <_return_int_size>: fe140c: 00 0b rts fe140e: e0 04 mov #4,r0 00fe1410 <_return_pointer_size>: fe1410: 00 0b rts fe1412: e0 04 mov #4,r0 00fe1414 <_return_short_size>: fe1414: 00 0b rts fe1416: e0 02 mov #2,r0 00fe1418 <_return_long_size>: fe1418: 00 0b rts fe141a: e0 04 mov #4,r0
そのサイズでの処理が一番適しているサイズが2ビットだったり4ビットだったりする
0x9001の01はPC相対で、大きなサイズの即値を格納している相対的な場所を指している
00fe141c <_return_short>: fe141c: 90 01 mov.w fe1422 <_return_short+0x6>,r0 ! 7788 fe141e: 00 0b rts fe1420: 00 09 nop fe1422: 77 88 add #-120,r7
では01ってどこから出ているのか。4+1*2
相対アドレス
mov.lで4バイトをPC相対でロードする際には,PCを4バイトアラインメント して,さらにオフセットを加算することでアドレスを計算している. (4バイトロードなので,アラインメントされる)
PCは1つ先の命令を指している。フェッチしたあと実行する。処理を早くするためにPCはさらに1つ先まで読んでおく。ただ、それが分岐命令だと先読みしたやつが無駄になってしまうので、遅延スロットでさらに実行しておく。遅延スロットは漢文でいうところのレ点。
PC相対=その命令の位置からの相対値
long return_long() { return 0x778899aa; }
00fe1424 <_return_long>: fe1424: d0 01 mov.l fe142c <_return_long+0x8>,r0 ! 778899aa fe1426: 00 0b rts fe1428: 00 09 nop fe142a: 00 09 nop fe142c: 77 88 add #-120,r7 fe142e: 99 aa mov.w fe1586 <_call_many_args+0xc>,r9 ! 1f11
(ただし非常に環境依存)
アラインメント=切り上げ 2を4で切り上げってなると4 6を4で切り上げってなると8 割り算をして割り切れなかったら次の倍数にする
mov.lとmov.wで、アクセスの方法が違う
@kozossakai 読書会でSHの部分を読んでいます。PC相対についてサイトで訂正がありましたが、それでもまだ気になる部分があります。アラインメントは切り上げが一般的と思いますが、切り下げられているようです。詳細をまとめました。 http://t.co/UMjfAn2No8
— 七誌 (@7shi) 2014, 12月 16
一般的にアラインメントでは切り上げすることが多いように思いますが、a: d0 00と1e: d0 01は切り下げでアラインメントされています。というわけで「切り下げ」を明記した方が誤解が少ないように思います
(この解釈が正しいかどうかは著者のアンサーによる)
相対アドレスはどこまで先まで指定できるのか
00-ff*4までなので、00-3fc
c→s→x→dでs(アセンブラ)を極大まで弄る
_return_short: .LFB9: .loc 1 37 0 .loc 1 39 0 mov.w .L9,r0 !, rts nop nop nop nop nop ...(ずっとnopをやってみる 256個nopを入れてみる) nop nop .align 1 .L9: .short 30600
付加するビット部分は元の値の最上位ビットで埋める(符号拡張)
short return_short_upper() { return 0xffee; } long return_long_upper() { return 0xffeeddcc; }
00fe1430 <_return_short_upper>: fe1430: 00 0b rts fe1432: e0 ee mov #-18,r0 00fe1434 <_return_long_upper>: fe1434: d0 01 mov.l fe143c <_return_long_upper+0x8>,r0 ! ffeeddcc fe1436: 00 0b rts fe1438: 00 09 nop fe143a: 00 09 nop fe143c: ff ee .word 0xffee fe143e: dd cc mov.l fe1770 <_erodata+0x174>,r13
オペランドとして指定できる即値は1バイト
符号計算を多用することで、命令サイズを削減するのが狙い。
なので、以下3つのワードは覚えておくとよいでしょう。他のCPUでも出てくるから。
// int aがr4 int return_arg1(int a) { return a; } // int aがr4 int bがr5 int return_arg2(int a, int b) { return b; }
00fe1440 <_return_arg1>: fe1440: 00 0b rts fe1442: 60 43 mov r4,r0 00fe1444 <_return_arg2>: fe1444: 00 0b rts fe1446: 60 53 mov r5,r0
int add(int a, int b) { return a + b; } int add3(int a, int b, int c) { return a + b + c; }
// r0 = r4 + r5
r0 = r4
r0 += r5
00fe1448 <_add>: fe1448: 60 43 mov r4,r0 fe144a: 00 0b rts fe144c: 30 5c add r5,r0 00fe144e <_add3>: fe144e: 60 43 mov r4,r0 fe1450: 30 5c add r5,r0 fe1452: 00 0b rts fe1454: 30 6c add r6,r0
P130
void null() { return; } int return_zero() { return 0; } int return_one() { return 1; }
00fe1400 <null>: fe1400: e1a0f00e mov pc, lr 00fe1404 <return_zero>: fe1404: e3a00000 mov r0, #0 fe1408: e1a0f00e mov pc, lr 00fe140c <return_one>: fe140c: e3a00001 mov r0, #1 fe1410: e1a0f00e mov pc, lr
アセンブラ上の機械語コードはe1a0f00eで、実行形式上の機械語コードは0ef0a0e1となっていて逆になっている
00fe1400 <null>: fe1400: e1a0f00e mov pc, lr 00fe1404 <return_zero>: fe1404: e3a00000 mov r0, #0 fe1408: e1a0f00e mov pc, lr 00fe140c <return_one>: fe140c: e3a00001 mov r0, #1 fe1410: e1a0f00e mov pc, lr