Язык ассемблера Quine


21

Напишите кратчайшую из возможных статей на ассемблере .

Используйте любой ISA, который вы хотите, если у него нет print-quineинструкции или эквивалента. Примеры включают в себя x86, MIPS, SPARC, MMIX, IBM BAL, MIX, VAX, JVM, ARM и т. Д.

Вы можете ссылаться на _printfфункцию стандартной библиотеки C (или эквивалент Java для байт-кода JVM) для ввода / вывода.

Длина будет определяться как по количеству команд, так и по размеру сегмента данных. Решения должны содержать как минимум две инструкции.

Квин должен печатать код сборки , а не собранный машинный код.


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

Кажется, все же правее, чем у меня ;-)
Joey

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

К сожалению, Жасмин не допускает столько приятных трюков, сколько ilasmпозволяет Microsoft . Но у JVM есть шесть различных 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) - ldcкороче bipushили iconst_*.
  • 2011-02-07 02:30 (952) - Кто сказал, что мне нужно наследовать от java.lang.Object? Другие имена классов намного короче :-)

4

газ для Linux x86 (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содержит файл дословно в текущем местоположении. Если вы используете это для включения самого исходного кода, вы получите хороший quine.


3

Формат Windows .COM: 307 символов

Собирает, используя A86, до 51 байта. Не требует никаких внешних библиотек, кроме функции DOS Int21 AH = 9 (записать строку в стандартный вывод).

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) Хотя хорошая реализация. Возможно, вы захотите включить un-db'd источник сборки, чтобы другие зрители получили прямой взгляд.
JB

@JB: я не включал CR \ NL. Глядя на это сейчас, я действительно должен был поместить данные в одну строку БД. Это сделало бы его меньше.
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) - dupкороче, чем писать ldloc.1каждый раз.
  • 2011-02-06 17:24 (669) - Мне не нужны пробелы после любого литерала, и такие вещи, как ldloc.1можно написать, ldloc 1чтобы сделать последний токен литералом. Результирующий байт-код, вероятно, больше, но он касается кода ассемблера, поэтому мне наплевать :-)
  • 2011-02-06 17:34 (623) - мне не нужна object[]локальная переменная; Я могу сделать все это в стеке напрямую. Ницца.

Похоже, вы удалили объект [] из неотформатированной версии, но не отформатированной ...
Aurel Bílý

@ Aurel: Действительно, как уже отмечалось, отформатированный - это самая первая версия. Идея все та же, поэтому я не буду обновлять ее снова.
Джои,

2

газ для Linux x86, 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. ( -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 / put вы фактически зависите от стандартного пролога / эпилога C, который явно не разрешен. И ИМХО не должно было быть; но у меня есть главный ответ: очевидно, я предвзятый :-)
JB

Что ж, можно утверждать, что использование C prolog / epilog неявно разрешено из-за упоминания использования printf (). Функции libc не всегда ведут себя надежно, если вы обходите C пролог / эпилог. На самом деле в моей системе ваша версия не работает, если я перенаправлю вывод в файл, потому что stdout сбрасывается только в коде C-эпилога. (Если бы вместо этого мы использовали write (), который является просто оболочкой для системного вызова, он бы работал в любом случае.)
breadbox

Прошло довольно много времени, но, похоже, я вспомнил, что разрешение на использование функций C было для меня неожиданностью: из-за этого проблема стала звучать нечисто. ОП тоже давно не было; сейчас будет сложно запросить разъяснения.
JB

Обратите внимание, что ABI позволяет printfзасорять свои аргументы в стеке. Технически небезопасно просто callповторять и ожидать те же аргументы, но на практике это работает, потому что gcc / clang никогда не использует слоты args в качестве пустого места, AFAIK.
Питер Кордес

Кроме того, в общем случае небезопасно вызывать printfиз _start(например, в статическом двоичном файле), так что это хороший аргумент для написания mainвместо a _start. Этот ответ объясняет различные способы связывания libc из статических или динамических двоичных файлов. (В динамическом двоичном файле Linux динамический компоновщик будет запускать функции инициализатора glibc, так что вы можете использовать его printfс _startточки входа, но это не относится к cygwin IIRC.)
Питер Кордес

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, rbpи leave. Вы также можете использовать более короткие названия меток. .Cs3 символа, когда 1 будет хорошо.
Питер Кордес

После этого, .att_syntax noprefixвероятно, больше не окупается. .intel_syntax noprefixпозволил бы вам отбросить эти шесть $префиксов тоже. но, вероятно, все еще не стоит. (Вы могли бы использовать lea ecx,.Csвместо синтаксиса Intel mov ecx,offset .Cs)
Питер Кордес

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.