汇编语言奎因


20

写出尽可能短的汇编语言quine

除非有print-quine说明或等效说明,否则请使用所需的任何ISA 。示例包括x86,MIPS,SPARC,MMIX,IBM BAL,MIX,VAX,JVM,ARM等。

您可以针对_printfI / O 链接到C标准库的功能(或Java等效于JVM字节码的功能)。

长度将根据指令数和数据段的大小进行判断。解决方案必须至少包含两个说明。

奎纳应该打印出汇编代码,而不是印刷的机器代码。


3
哦,哇,这听起来像个强壮的家伙
匿名的胆小鬼

Answers:


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


现在,这令人沮丧:-(
Joey

1
我通常会说“适合工作的工具”,但话又说回来,这里感觉不对:D
JB

似乎比我更正确;-)
Joey

5

JVM字节码议会(通过茉莉) - 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不允许使用微软ilasm允许的许多精美技巧。但是JVM总共有6条不同的dup指令,可以执行各种有趣的事情。.NET似乎不支持对堆栈中的项目进行重新排序。

无论如何,我想我的两个条目都不是最短代码的重要竞争者,但我想很难使它们更短。因此,出于完整性考虑:-)

评论版本,其中包含有关堆栈内容的信息:

.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)– ldcbipush或短iconst_*
  • 2011-02-07 02:30(952)–谁说我需要从java.lang.Object继承?其他类的名称要短得多:-)

4

适用于x86 Linux的气体(89字节,七个指令)

从技术上讲,这是作弊。

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)不错的实现。您可能希望包括undb'd程序集源,以便其他查看器直接看。
JB

@JB:我没有包括CR \ NL。现在来看,我确实应该将数据放入单个db行中。这样可以缩小尺寸。
Skizz

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)– dupldloc.1每次写作都要短。
  • 2011-02-06 17:24(669)–我不需要在任何文字后加空格,ldloc.1可以编写类似的东西ldloc 1以使最后一个标记成为文字。产生的字节码可能更大,但这是关于汇编程序代码的,所以我不在乎:-)
  • 2011-02-06 17:34(623)–我不需要将object[]用作局部变量;我可以直接在堆栈上完成所有操作。真好

似乎您已从未格式化的版本中删除了object [],但未从格式化的版本中删除了该对象[]
AurelBílý2011年

@Aurel:确实,如前所述,格式化的是第一个版本。这个想法仍然是相同的,因此我将不再进行更新。
乔伊,

2

x86 Linux的gas,184176字节

.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。(-m32如果您的操作系统已经是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 prolog / epilog,这是明确不允许的。恕我直言,本来就不是。但我得到了最高的答案:很明显我有偏见:-)
JB 2012年

嗯,由于提到了使用printf(),因此可能会争辩说隐式允许使用C prolog / epilog。如果绕过C prolog / epilog,libc函数并不总是可靠地运行。实际上,在我的系统上,如果我将输出通过管道传输到文件,则您的版本将不起作用,因为stdout仅在C Epilog代码中被刷新。(如果我们改为使用write(),它只是围绕syscall的包装,无论哪种方式都可以工作。)
面包店

现在已经很长一段时间了,但是我似乎记得当时允许使用C函数令我感到惊讶:这确实使问题听起来不纯。OP也已经存在很长时间了。现在将很难要求澄清。
JB 2012年

注意,ABI允许printf在堆栈上破坏其args。call再次使用它并期望使用相同的args在技术上并不安全,但是它在实践中可行,因为gcc / clang从未将args插槽用作暂存空间,即AFAIK。
彼得·科德斯

另外,通常也不安全地printf_start(例如,在静态二进制文件中)进行调用,因此这对于编写a main而不是a 是一个很好的论据_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,系统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。您也可以使用较短的标签名称。 .Cs如果1可以,则为3个字符。
彼得·科德斯

在那之后,.att_syntax noprefix可能不再为自己付出代价。 .intel_syntax noprefix也会让您删除这六个$前缀。但可能仍然不值得。(您可以使用它lea ecx,.Cs代替intel语法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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.