2

これが以前に行われたかどうかに興味があり、必ずしも実用的な価値があるかどうかはわかりません (ただし、空間効率の向上は明らかです)。同じマシンコード内で複数の命令をエンコードしたことがありますか? 例えば:

(これは完全に作り物です)

0xAEA2 -> R3 0xA2 を追加

0xEAE6 -> mov R1 0xE6

0xAAAA ...

1 ニブルを左にシフトしてマシン コードを再解釈すると、次のようになります。

0xEA2E -> mov R1 0x2E

0xAE5A -> R3 0x5A を追加

4

3 に答える 3

4

Smalltalk 78 (現代のすべての Smalltalk 方言の前身の 1 つ) の実装では、2 バイトのstore argument 0バイトコードがあり、その 2 番目のバイトはload argument 0でした。このように、ストア命令の先頭にジャンプしたコードはストアを実行し、その途中(!) にジャンプしたコードはロードを実行しました。これについては、 Reviving Smalltalk-78 - Bert Freudenberg - IWST 2014 -around minutes 30-で詳しく知ることができます。

于 2014-12-19T17:05:41.950 に答える
1

これは新しいことではありません。何年も前に、小規模なコード最適化コンテストを開催していました。たとえば、次のコードは、C 関数strcpystrncpy、およびstpcpyをわずか 42 バイトで実装しています。これは 1993 年に書きました。16 ビット 8086 アセンブリ言語、C 呼び出し可能、パラメーターがスタックに渡され、呼び出し元がスタックをクリーンアップします。

のエントリ ポイントがstrcpy命令の最初のバイトであり、次の 2 バイトが AX レジスタにロードされることに注意してください。そして、db 3Chは別の命令の最初のバイトであり、次のバイト ( or al)を消費し、 によって実行される命令STCの 2 番目のバイトであるor al,0F9h命令を実行しstrncpyます。

リスト ファイルを作成してオペコードを取得し、3 つのエントリ ポイントのそれぞれで何が起こっているかを追跡することは有益です。

この種のトリックは、既存のコードにパッチを適用するときに役立ちました。場合によっては、重要な部分のアドレスを変更せずに、.COM ファイルにバイナリ パッチを作成できます。これは、16 バイト (またはそれ以上) に揃える必要がある場合に重要であり、別の命令を追加できるようにするためだけに 15 バイトのデッド スペースを浪費するという打撃を受けたくありませんでした。ああ、64K バイトしかないときにプレイするゲームです。

   Ideal
   Model Small,c
   CodeSeg

   Public strcpy,strncpy,stpcpy
 ;
 ; 42 bytes

 ;
 ; char * strcpy (char *dest, char *src);
 ;
 strcpy:
   db 0B8h       ;mov ax,immed
 ;
 ; char * stpcpy (char *dest, char *src);
 ;
 stpcpy:
   mov al,0Ch    ;0Ch is the opcode for OR AL,immediate
   mov cx,0ffffh ;make max count
   db 3Ch        ;cmp al,immediate
                 ;stpcpy  - CF set, ZF set
                 ;strcpy  - CF set, ZF clear
 ;
 ; char * strncpy (char *dest, char *src, unsigned len);
 ;
 strncpy:
   or al,0F9h    ;strncpy - CF clear, ZF clear
                 ;0F9h is the opcode for STC,
                 ;which is executed by strcpy and stpcpy
   pop dx        ;return address in DX
   pop bx        ;dest string in BX
   pop ax        ;source string in AX
   jc l0         ;if strncpy
   pop cx        ;then get length in CX
   push cx       ;and fixup stack
 l0:
   push ax       ;more stack fixup
   push bx       ;save return value
   push si       ;gotta save SI
   xchg si,ax    ;SI points to source string
   lahf          ;save flags for exit processing
 l1:
   lodsb         ;get character
 l2:
   jcxz Done     ;done if count = 0
   mov [bx],al   ;store character
   inc bx        ;bump dest
   or al,al      ;if character is 0 or
   loopnz l1     ;if at end of count, then done
   sahf          ;restore flags
   ja l2         ;for strncpy(), must loop until count reached
 Done:
   pop si        ;restore SI
   pop ax        ;return value in AX
   jnz AllDone   ;done if not stpcpy
   xchg ax,bx    ;otherwise return pointer to
   dec ax        ;end of string
 AllDone:
   call dx       ;return to caller

 End

これらのコンテストでいつも私を打ち負かしていた私の友人を困らせるためだけに、そのアイデアを思いつくのに何時間も費やしたことを覚えています. 彼は数分間それを見て、それから別のバイトを剃りました.

于 2014-12-20T15:37:10.350 に答える