アセンブリ言語クイン


20

可能な限り短いアセンブリ言語のquineを書きます。

print-quine命令または同等のものがない限り、必要なISAを使用します。例には、x86、MIPS、SPARC、MMIX、IBM BAL、MIX、VAX、JVM、ARMなどが含まれます。

_printfI / O のC標準ライブラリの関数(またはJVMバイトコードに相当するJava)に対してリンクできます。

長さは、命令数とデータセグメントのサイズの両方で判断されます。ソリューションには少なくとも2つの指示が含まれている必要があります。

QUINEを印刷する必要があり、アセンブリコードではなく、組み立てられたマシンコード。


3
ああ、これは難しいように聞こえます
匿名の

回答:


20

x86 Linux、AT&T構文:244

push $10
push $34
push $s
push $34
push $37
push $37
push $s
call printf
mov $0,%ebx
mov $1,%eax
int $128
s:.ascii "push $10
push $34
push $s
push $34
push $37
push $37
push $s
call printf
mov $0,%cebx
mov $1,%ceax
int $128
s:.ascii %c%s%c%c"

(私はこれでそれをコンパイル:gcc -nostartfiles -lc quine.S -o quine


それは憂鬱です、今:-(
ジョーイ

1
私は通常「仕事に適したツール」と言いますが、それでもここでは正しくないと感じます:D
JB

しかし、私のものよりも正しいようです;
ジョーイ

5

JVMバイトコードアセンブリ(Jasmin経由)– 952 960 990

.class public Q
.super java/io/File
.method public static main([Ljava/lang/String;)V
.limit stack 9
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc ".class public Q%n.super java/io/File%n.method public static main([Ljava/lang/String;)V%n.limit stack 9%ngetstatic java/lang/System/out Ljava/io/PrintStream;%nldc %c%s%c%nldc 3%nanewarray java/lang/Object%ndup%ndup%nldc 0%nldc 34%ninvokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;%ndup_x2%naastore%nldc 2%nswap%naastore%ndup2%nswap%nldc 1%nswap%naastore%ninvokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;%npop%nreturn%n.end method"
ldc 3
anewarray java/lang/Object
dup
dup
ldc 0
ldc 34
invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;
dup_x2
aastore
ldc 2
swap
aastore
dup2
swap
ldc 1
swap
aastore
invokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
pop
return
.end method

悲しいことに、JasminはMicrosoftが許可するほど多くの素晴らしいトリックを許可していませんilasm。しかし、JVMには、あらゆる種類の楽しいことを行う合計6つの異なるdup命令があります。スタック上のアイテムの並べ替えは、.NETがサポートしていないようです。

いずれにせよ、私の2つのエントリはどれも最短コードの深刻な候補ではないと思いますが、もっと短くするのは難しいと思います。したがって、完全を期すために:-)

スタックの内容に関する情報を含むコメント付きバージョン:

.class public Q
.super java/io/File
.method public static main([Ljava/lang/String;)V
.limit stack 9
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc ".class public Q%n.super java/io/File%n.method public static main([Ljava/lang/String;)V%n.limit stack 9%ngetstatic java/lang/System/out Ljava/io/PrintStream;%nldc %c%s%c%nldc 3%nanewarray java/lang/Object%ndup%ndup%nldc 0%nldc 34%ninvokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;%ndup_x2%naastore%nldc 2%nswap%naastore%ndup2%nswap%nldc 1%nswap%naastore%ninvokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;%npop%nreturn%n.end method"
ldc 3       ; stack; System.out, string, 3
anewarray java/lang/Object    ; stack: System.out, string, Object[3]
dup
dup    ; stack: System.out, string, array, array, array
ldc 0  ; stack: System.out, string, array, array, array, 0
ldc 34   ; stack: System.out, string, array, array, array, 0, 34
invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;
dup_x2   ; stack: System.out, string, array, array, 34, array, 0, 34
aastore  ; stack: System.out, string, array, array, 34
ldc 2    ; stack: System.out, string, array, array, 34, 2
swap     ; stack: System.out, string, array, array, 2, 34
aastore  ; stack: System.out, string, array
dup2     ; stack: System.out, string, array, string, array
swap     ; stack: System.out, string, array, array, string
ldc 1    ; stack: System.out, string, array, array, string, 1
swap     ; stack: System.out, string, array, array, 1, string
aastore  ; stack: System.out, string, array
invokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
pop
return
.end method

歴史:

  • 2011-02-07 02:09(990)–最初の作業バージョン。
  • 2011-02-07 02:11(960)– またはldcより短い。bipushiconst_*
  • 2011-02-07 02:30(952)– java.lang.Objectから継承する必要があると言うのは誰ですか?他のクラス名はとても短いです:-)

4

x86 Linuxのガス(89バイト、7つの命令)

技術的には、これは不正行為です。

mov $4,%al
mov $1,%bl
mov $b,%ecx
mov $89,%dl
int $128
mov %bl,%al
int $128
b:.incbin"a"

という名前のファイルに保存aし、次のコマンドでアセンブルして、という名前の実行可能ファイルを作成しますa.out

as -o a.o ; ld a.o

このディレクティブに.incbinは、現在の場所に逐語的にファイルが含まれています。これを使用してソースコード自体を含めると、すばらしい結果が得られます。


3

Windows .COM形式:307文字

A86を使用して51バイトにアセンブルします。DOS Int21 AH = 9関数(stdoutに文字列を書き込む)以外の外部ライブラリは必要ありません。

db 185
db  51
db   0
db 190
db   0
db   1
db 191
db  47
db   1
db 172
db 178
db  10
db 199
db   6
db  45
db   1
db  32
db  32
db 180
db   0
db 246
db 242
db 128
db 196
db  48
db 136
db  37
db  79
db  10
db 192
db 117
db 242
db 180
db   9
db 186
db  42
db   1
db 205
db  33
db 226
db 221
db 195
db 100
db  98
db  32
db  32
db  51
db  49
db  10
db  13
db  36

357バイトをカウントするのが怖いです。(そしてあなたのプログラムは実際に408を出力します)しかし、素晴らしい実装です。他の視聴者が直接見られるように、DB化されていないアセンブリソースを含めることができます。
JB

@JB:CR \ NLは含めませんでした。今見てみると、データを単一のdb行に入れる必要があります。それは小さくなります。
スキズ

3

NASM、223バイト

%define a "%define "
%define b "db "
%define c "%deftok "
%define d "a, 97, 32, 34, a, 34, 10, a, 98, 32, 34, b, 34, 10, a, 99, 32, 34, c, 34, 10, a, 100, 32, 34, d, 34, 10, c, 101, 32, 100, 10, b, 101, 10"
%deftok e d
db e

受け入れられた答えを破りました!


2

.NET CIL – 623 669 691 723 727

.assembly H{}.method void M(){.entrypoint.locals init(string)ldstr".assembly H{0}{1}.method void M(){0}.entrypoint.locals init(string)ldstr{2}{3}{2}stloc 0ldloc 0ldc.i4 4newarr object dup dup dup dup ldc.i4 0ldstr{2}{0}{2}stelem.ref ldc.i4 1ldstr{2}{1}{2}stelem.ref ldc.i4 2ldc.i4 34box char stelem.ref ldc.i4 3ldloc 0stelem.ref call void[mscorlib]System.Console::Write(string,object[])ret{1}"stloc 0ldloc 0ldc.i4 4newarr object dup dup dup dup ldc.i4 0ldstr"{"stelem.ref ldc.i4 1ldstr"}"stelem.ref ldc.i4 2ldc.i4 34box char stelem.ref ldc.i4 3ldloc 0stelem.ref call void[mscorlib]System.Console::Write(string,object[])ret}

単一行。最後に改行はありません。

最初のバージョンをフォーマットし、コメントを付けました(もうそれは馬鹿ではありませんが)–一般的な概念から大きく逸脱することはまずありません。

.assembly H{}
.method void M() {
  .entrypoint
  .locals init (
    string,
    object[]
  )
  // the string
  ldstr".assembly H{0}{1}.method void M(){0}.entrypoint.locals init(string,object[])ldstr{2}{3}{2}stloc.0 ldloc.0 ldc.i4.4 newarr object stloc.1 ldloc.1 ldc.i4.0 ldstr{2}{0}{2} stelem.ref ldloc.1 ldc.i4.1 ldstr{2}{1}{2} stelem.ref ldloc.1 ldc.i4.2 ldc.i4 34 box char stelem.ref ldloc.1 ldc.i4.3 ldloc.0 stelem.ref ldloc.1 call void[mscorlib]System.Console::Write(string,object[])ret{1}"
  stloc.0   // store in first local var
  ldloc.0   // load again. Going to be the first argument to Console::Write
  ldc.i4.4 newarr object stloc.1   // create new array and store in local var
  ldloc.1 ldc.i4.0 ldstr"{" stelem.ref   // we need a literal brace
  ldloc.1 ldc.i4.1 ldstr"}" stelem.ref   // closing, too
  ldloc.1 ldc.i4.2 ldc.i4 34 box char stelem.ref   // double quote
  ldloc.1 ldc.i4.3 ldloc.0 stelem.ref   // our format string from before
  ldloc.1 // load array
  call void[mscorlib]System.Console::Write(string,object[]) // output
  ret
}

歴史

  • 2011-02-06 16:48(727)–最初の作業バージョン。
  • 2011-02-06 17:14(723)–文字列リテラルの後にスペースは必要ありません。
  • 2011-02-06 17:21(691)– 毎回dup書くよりも短いですldloc.1
  • 2011-02-06は、夜05時24分(669) -私は後にスペースを必要としない任意のリテラルとのようなものldloc.1のように書くことができldloc 1リテラルトークン最後を作ること。結果のバイトコードはおそらくより大きくなりますが、アセンブラコードに関するものなので、あまり気にすることはできませんでした:-)
  • 2011-02-06 17:34(623)– object[]ローカル変数としては必要ありません。スタック上で直接すべてを行うことができます。いいね

フォーマットされた1 ...あなたがフォーマットされていないバージョンから] [オブジェクトを削除したように思えるが、ではない
オーレルビリー

@Aurel:実際、前述のように、フォーマットされたものは最初のバージョンです。考え方は同じなので、再度更新することはありません。
ジョーイ

2

x86 Linuxのガス、184 176バイト

.globl main
main:movw $34,B+87
push $B
call printf
call printf
pop B
ret
.data
B:.ascii".globl main
main:movw $34,B+87
push $B
call printf
call printf
pop B
ret
.data
B:.ascii"

でビルドしgcc -m32 -o a.out quine.Sます。(-m32OSが既に32ビットの場合、これはオプションです。)

追加して編集:ルールを変更して、puts代わりにprintf呼び出せるようにすると、182 174バイトで実行できます。

.globl main
main:movw $34,B+86
push $B+1
call puts
call puts
pop B
ret
.data
B:.ascii"
.globl main
main:movw $34,B+86
push $B+1
call puts
call puts
pop B
ret
.data
B:.ascii"

(これは、前のものとは異なり、終了改行があることに注意してください。)


短さに感謝します。しかし、printf / putsに加えて、実際には標準のCプロローグ/エピローグに依存しているという事実にだまされていると感じています。これは明示的に許可されていません。そして、私見はそうするつもりはありませんでした。しかし、私はトップの答えを持っています:明らかに私は偏っています:
JB

さて、printf()の使用について言及しているため、Cのprolog / epilogの使用は暗黙的に許可されていると主張できます。Cのprolog / epilogをバイパスした場合、libc関数は常に確実に動作するとは限りません。実際、私のシステムでは、出力をファイルにパイプすると、バージョンは機能しません。これは、stdoutがCエピローグコードでのみフラッシュされるためです。(代わりに、syscallの単なるラッパーであるwrite()を使用した場合、どちらの方法でも機能します。)
breadbox

かなり長い時間が経ちましたが、C関数が許可されたことは当時私にとって驚きだったことを思い出すようです。OPも長い間登場していません。今すぐ説明を要求するのは難しいでしょう。
JB

ABIではprintf、スタック上の引数を上書きできることに注意してください。技術的にcallは同じだけで同じ引数を期待するのは安全ではありませんが、gcc / clangは引数スロットをスクラッチスペースとして使用しないため、実際には機能します。
ピーターコーデス

また、一般的には、呼び出すことは安全ではないのですprintfから、_startそれは書くための良い引数であるので、(例えば、静的バイナリ中)mainの代わりに_startこの回答は、静的または動的バイナリからlibcをリンクするさまざまな方法を説明しています。(Linuxのダイナミックバイナリでは、ダイナミックリンカーがglibcの初期化関数を実行するためprintf_startエントリポイントから使用できますが、cygwin IIRCの場合はそうではありません。)
Peter Cordes

1

ブート可能なASM、660バイト

[bits 16]
mov ax,07C0h
mov ds,ax 
mov ah,0
mov al,03h 
int 10h
mov si,code
call p 
jmp $
p:mov ah,0Eh
r:lodsb
cmp al,0
je d
cmp bx,0x42
jne s
c:int 10h
jmp r
s: cmp al,94 
je re
cmp al,63
je q
jmp c
q:mov al,34
jmp c
re:push si
mov bx,0x42
mov si,code
call p 
mov bx,0
pop si
jmp p 
d:ret
code:db "[bits 16]\mov ax,07C0h\mov ds,ax\mov ah,0\mov al,03h\int 10h\mov si,code\call p\jmp $\p:mov ah,0Eh\r:lodsb\cmp al,0\je d\cmp bx,0x42\jne s\c:int 10h\jmp r\s:cmp al,94\je re\cmp al,63\je q\jmp c\q:mov al,34\jmp c\re:push si\mov bx,0x42\mov si,code\call p\mov bx,0\pop si\jmp p\\d:ret\\code:db ?^?\times 510-($-$$) db 0\dw 0xAA55"
times 510-($-$$) db 0
dw 0xAA55

もともとjdiez17によって、本当にあなたのゴルフです。


0

x86-64、System V AMD64 ABI、GASM:432

.att_syntax noprefix
.globl main
main:
pushq rbp
movq rsp, rbp
mov $.Cs, rdi
mov $0xa, rsi
mov $0x22, edx
mov $.Cs, ecx
mov $0x22, r8d
mov $0xa, r9d
xor eax, eax
call printf
xor eax, eax
leave
ret
.Cs: .string ".att_syntax noprefix
.globl main
main:
pushq rbp
movq rsp, rbp
mov $.Cs, rdi
mov $0xa, rsi
mov $0x22, edx
mov $.Cs, ecx
mov $0x22, r8d
mov $0xa, r9d
xor eax, eax
call printf
xor eax, eax
leave
ret%c.Cs: .string %c%s%c%c"

1
オペランド間のコンマの後にスペースは必要ありません。またxor eax,eax、プログラムの終了ステータスを気にしない場合は、まったく必要ありません。ゼロ以外のステータスで終了しても、それ自体を印刷します。のpush代わりに使用することもできますpushq。実際、なぜスタックフレームを作成しているのですか?push rbp/ mov rsp, rbpleave。をドロップします。短いラベル名を使用することもできます。 .Cs1で十分な場合は3文字です。
ピーターコーデス

その後、.att_syntax noprefixおそらくそれ以上の費用はかかりません。 .intel_syntax noprefixこれらの6つの$プレフィックスも削除できます。しかし、おそらくそれだけの価値はありません。(lea ecx,.Csintel-syntaxの代わりに使用できますmov ecx,offset .Cs
Peter Cordes

0

TAL

push puts
push \100
push {push puts
push \100
push {@}
dup
strmap
invokeStk 2}
dup
strmap
invokeStk 2

実行するに::tcl::unsuppoted::assembleは、コードを引数として呼び出します。
Tcl 8.6のみ。


3
バイト数を含める必要があります。
MD XF

0

80x86 TASM、561バイト

MODEL TINY
.CODE
.STARTUP
DB 177
DB 076
DB 186
DB 044
DB 001
DB 172
DB 180
DB 036
DB 179
DB 004
DB 191
DB 080
DB 001
DB 079
DB 136
DB 037
DB 212
DB 010
DB 004
DB 048
DB 134
DB 196
DB 075
DB 117
DB 244
DB 180
DB 009
DB 205
DB 033
DB 178
DB 071
DB 226
DB 228
DB 178
DB 038
DB 205
DB 033
DB 195
DB 013
DB 010
DB 069
DB 078
DB 068
DB 036
DB 077
DB 079
DB 068
DB 069
DB 076
DB 032
DB 084
DB 073
DB 078
DB 089
DB 013
DB 010
DB 046
DB 067
DB 079
DB 068
DB 069
DB 013
DB 010
DB 046
DB 083
DB 084
DB 065
DB 082
DB 084
DB 085
DB 080
DB 013
DB 010
DB 068
DB 066
DB 032
END
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.