68000 アセンブラテクニックその1

データ分離して逆アセンブルした状態で、プログラムから置換をするという試行. プログラム全体の流れをみることはないので正常動作としては100%同じ動作になることを優先.

clr.l dn

moveq #0,dn

move.l #imm,dn

imm は -0x80 から 0x7f に限る.

moveq #imm,dn

(add|sub)[ai]?.[bwl] #imm,ea

imm は 1 から 8 に限る. moveq と違って ea の制限が少ない.

(add|sub)q.[bwl] #imm,ea

(jsr|bsr) ea; rts

削除する rts にラベルが登録してない場合に限る.

(jmp|bra) ea

(jsr|jmp|lea) abs(,an)?

jsr,jmp,lea で例が多いので ea 次第では他の命令で利用可能.

ea が -0x8000から0x7fffの場合
(jsr|jmp|lea) abs.w(,an)?
ea が pc+2 との距離が -0x8000から0x7fffの場合
(jsr|jmp|lea) (pc,ea),an

bCC ea

bsr ではなく, ea と pc+2 の距離が 0 の場合
(削除)
ea と pc+2 の距離が -0x80 から 0x7e の場合
bCC.s ea
  • 元のプログラム作成側では省略すると .w になっていたような挙動なので削ることが結構できる.
  • 私が利用しているアセンブラの機能として .s か .w を書かないと最短にしてくれるがアセンブルに時間が異様にかかる.

jump table 共通次項

下記の命令を想定.

	lea	table.l,an
	move.w	ram,dn
	lsl.w	#2,dn
	movea.l	(an,dn),an
	jmp	(an)
table:
	dc.l	pointer0,pointer1,...

jump table が近い場合

  • jmp/jsr の pc+2 との距離が table が -0x80 から 0x7e の場合. jsr は近くにないことがある.
  • addressing (offset,pc,ix) を使うため offset が狭い.
pointer と bra.s の PC + 2 との距離が -0x80 から 0x7e で収まる場合
	move.w	ram,dn
	lsl.w	#1,dn
	jmp	(table,pc,dn.w)
table:
	bra.s	pointer0
	bra.s	pointer1

命令数は減るが実行数は変わらないと思う.

pointer の値が -0x8000 から 0x7ffe で収まる場合
	move.w	ram,dn
	lsl.w	#1,dn
	movea.w	(table,pc,dn.w),an
	jmp	(an)
table:
	dc.w	pointer0
	dc.w	pointer1
pointer と table の距離が -0x8000 から 0x7ffe で収まる場合
	move.w	ram,dn
	lsl.w	#1,dn
	movea.w	(table,pc,dn.w),an
	jmp	(table,pc,an.l)
table:
	dc.w	pointer0 - table
	dc.w	pointer1 - table

jump table が遠い場合

pointer と bra.s の PC + 2 との距離が -0x80 から 0x7e で収まる場合
	lea	table,an ;先述の table.w, pc(table) も併用する
	move.w	ram,dn
	lsl.w	#1,dn
	jmp	(an,dn.w)
	...
	...
	...
table:
	bra.s	pointer0
	bra.s	pointer1
pointer の値が -0x8000 から 0x7ffe で収まる場合
	lea	table,an ;同上
	move.w	ram,dn
	lsl.w	#1,dn
	movea.w	(an,dn.w),an
	jmp	(an)
	...
	...
	...
table:
	dc.w	pointer0
	dc.w	pointer1

pc に関わらず利用できる.

pointer と table の距離が -0x8000 から 0x7ffe で収まる場合
	lea	table,an ;同上
	move.w	ram,dn
	lsl.w	#1,dn
	adda.w	(an,dn.w),an
	jmp	(an)
	...
	...
	...
table:
	dc.w	pointer0 - table
	dc.w	pointer1 - table

これはあまりいいものが思いつかなかった.

pointer が上記の方法で16bit以下に収まらない場合

pointer の最大値と最小値の差が 0x10000 未満の場合
center	set	pointer.min + (pointer.max - pointer.min) / 2
	lea	table,an ;同上
	move.w	ram,dn
	lsl.w	#1,dn
	movea.w	(an,dn.w),an
 if center < 0x8000
	jmp	(an,center)
 else
	adda.l	#center,an
	jmp	(an)
 endif
table:
	dc.w	pointer0 - center
	dc.w	pointer1 - center

一応動作確認したが pointer の最大値と最小値を算出するのはビルドの過程で効率が悪すぎる. table の中身が奇数になることもありちょっと変. また adda.l が増えるので遅いので実用に向いていない.