Język asemblera

21

Napisz możliwie najkrótszą quine w języku asemblera .

Użyj dowolnego ISA, jeśli chcesz, chyba że ma print-quineinstrukcję lub równoważny. Przykłady obejmują x86, MIPS, SPARC, MMIX, IBM BAL, MIX, VAX, JVM, ARM itp.

Możesz połączyć się z _printffunkcją biblioteki standardowej C (lub odpowiednikiem Java dla kodu bajtowego JVM) dla I / O.

Długość będzie oceniana zarówno na podstawie liczby instrukcji, jak i wielkości segmentu danych. Rozwiązania muszą zawierać co najmniej dwie instrukcje.

Quine powinna wydrukować kod zestawu , a nie zmontowany kod maszyny.

Hoa Long Tam
źródło
3
Och, wow, to brzmi jak twardy
anonimowy tchórz

Odpowiedzi:

20

Linux x86, 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"

(Skompilowałem to z tym gcc -nostartfiles -lc quine.S -o quine:)

JB
źródło
To przygnębiające, teraz :-(
Joey
1
Zwykle mówię „odpowiednie narzędzie do pracy”, ale z drugiej strony tutaj nie wydaje się właściwe: D
JB
Wydaje się jednak mieć więcej racji niż moja ;-)
Joey
5

Zestaw JVM Bytecode (przez 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

Niestety, Jasmin nie dopuszcza tylu fajnych sztuczek, na jakie ilasmpozwala Microsoft . Ale JVM ma w sumie sześć różnych dupinstrukcji, które wykonują różnego rodzaju zabawne rzeczy. Zmiana kolejności elementów na stosie jest czymś, czego .NET nie obsługuje.

W każdym razie wydaje mi się, że żaden z moich dwóch wpisów nie stanowi poważnego pretendenta do najkrótszego kodu, ale wydaje mi się, że trudno jest je znacznie skrócić. Dlatego właśnie dla kompletności :-)

Skomentowana wersja z informacjami o tym, co jest na stosie:

.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

Historia:

  • 2011-02-07 02:09 (990) - Pierwsza działająca wersja.
  • 2011-02-07 02:11 (960) - ldcjest krótszy niż bipushlub iconst_*.
  • 2011-02-07 02:30 (952) - Kto powiedział, że muszę odziedziczyć po java.lang.Object? Inne nazwy klas są o wiele krótsze :-)
Joey
źródło
4

gas dla x86 Linux (89 bajtów, siedem instrukcji)

Technicznie jest to oszustwo.

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

Zapisz w pliku o nazwie ai złóż za pomocą następujących poleceń, aby utworzyć plik wykonywalny o nazwie a.out.

as -o a.o ; ld a.o

Dyrektywa .incbinzawiera dosłownie plik w bieżącej lokalizacji. Jeśli użyjesz tego do dołączenia samego kodu źródłowego, otrzymasz niezłą quine.

FUZxxl
źródło
3

Format Windows .COM: 307 znaków

Składa za pomocą A86 do 51 bajtów. Nie wymaga bibliotek zewnętrznych innych niż funkcja DOS Int21 AH = 9 (zapisz ciąg znaków na standardowe wyjście).

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
Skizz
źródło
Obawiam się, że liczę 357 bajtów. (a twój program faktycznie generuje 408) Jednak niezła implementacja. Możesz dołączyć źródło asemblera un-db'd, aby inne osoby przeglądające miały bezpośredni wgląd.
JB
@JB: Nie uwzględniłem CR \ NL. Patrząc na to teraz, naprawdę powinienem umieścić dane w jednej linii db. To by go zmniejszyło.
Skizz
3

NASM, 223 bajty

%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

Pokonując przyjętą odpowiedź!

MD XF
źródło
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}

Pojedyncza linia, bez końca linii na końcu.

Sformatowana i skomentowana pierwsza wersja (mimo że nie jest to już quine) - jest mało prawdopodobne, że znacznie odbiegam od ogólnej koncepcji:

.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
}

Historia :

  • 2011-02-06 16:48 (727) - Pierwsza działająca wersja.
  • 2011-02-06 17:14 (723) - Nie potrzebuję spacji po dosłownym łańcuchu znaków.
  • 2011-02-06 17:21 (691) - dupjest krótszy niż pisanie za ldloc.1każdym razem.
  • 2011-02-06 17:24 (669) - Nie muszę obowiązuje po dowolny dosłowny i rzeczy, jak ldloc.1można zapisać ldloc 1się, aby ostatni żeton dosłownym. Wynikowy kod bajtowy jest prawdopodobnie większy, ale dotyczy kodu asemblera, więc nie obchodzi mnie to mniej :-)
  • 2011-02-06 17:34 (623) - Nie potrzebuję object[]zmiennej lokalnej; Mogę to wszystko zrobić bezpośrednio na stosie. Ładny.
Joey
źródło
Wygląda na to, że usunąłeś obiekt [] z niesformatowanej wersji, ale nie sformatowanej ...
Aurel Bílý
@Aurel: Rzeczywiście, jak wspomniano, sformatowana jest pierwsza wersja. Pomysł jest nadal ten sam, więc nie będę go aktualizować ponownie.
Joey,
2

gas dla x86 Linux, 184 176 bajtów

.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"

Buduj z gcc -m32 -o a.out quine.S. (Opcja -m32jest opcjonalna, jeśli Twój system operacyjny jest już 32-bitowy.)

Edytowano, aby dodać: Jeśli zmodyfikujemy reguły, aby umożliwić putswywoływanie zamiast printf, można to zrobić w 182 174 bajtach:

.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"

(Zauważ, że ten, w przeciwieństwie do poprzedniego, ma nową linię kończącą.)

chlebak
źródło
Doceniam krótkość. Ale czuję się oszukany przez fakt, że oprócz printf / puts, faktycznie zależysz od standardowego prologu / epilogu C, co nie jest wyraźnie dozwolone. I IMHO nie miało być; ale mam najlepszą odpowiedź: oczywiście jestem stronniczy :-)
JB
Cóż, można argumentować, że użycie prologu / epilogu C jest domyślnie dozwolone, ze względu na wzmiankę o użyciu printf (). Funkcje libc nie zawsze zachowują się niezawodnie, jeśli pominiesz prolog / epilog C. W rzeczywistości w moim systemie twoja wersja nie działa, jeśli przesyłam dane wyjściowe do pliku, ponieważ stdout jest opróżniany tylko w kodzie epilogu C. (Gdybyśmy zamiast tego użyli write (), który jest po prostu otoką wywołania systemowego, działałoby to w obu kierunkach.)
breadbox
Minęło już sporo czasu, ale wydaje mi się, że przypominanie sobie, że dozwolone funkcje C było dla mnie niespodzianką: sprawiło, że problem brzmiał trochę nieczysto. Od dawna nie było też OP; trudno będzie teraz poprosić o wyjaśnienia.
JB
Zauważ, że ABI pozwala printfna spychanie swoich argumentów na stosie. Nie jest technicznie bezpieczne, aby callto powtórzyć i oczekiwać tych samych argumentów, ale działa w praktyce, ponieważ gcc / clang nigdy nie używa szczelin argumentów jako miejsca na zarysowania, AFAIK.
Peter Cordes
Ponadto, generalnie nie jest bezpiecznie wywoływać printfz _start(np. W statycznym pliku binarnym), więc jest to dobry argument do napisania mainzamiast _start. Ta odpowiedź wyjaśnia różne sposoby łączenia libc ze statycznych lub dynamicznych plików binarnych. (W dynamicznym pliku binarnym systemu Linux dynamiczny linker uruchomi funkcje inicjalizujące glibc, więc możesz używać go printfod _startpunktu wejścia, ale nie jest tak w przypadku cygwin IIRC.)
Peter Cordes
1

Rozruchowy ASM, 660 bajtów

[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

Oryginalnie autorstwa jdiez17 , twoja gra w golfa naprawdę.

MD XF
źródło
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"
Lxgr
źródło
1
Nie potrzebujesz spacji po przecinku między operandami. I wcale nie potrzebujesz, xor eax,eaxjeśli nie obchodzi cię status wyjścia z programu. Nadal drukuje się, nawet jeśli zakończy działanie z niezerowym statusem. Możesz także użyć pushzamiast pushq. Właściwie, dlaczego w ogóle robisz ramkę stosu? Upuść push rbp/ mov rsp, rbpi leave. Możesz także użyć krótszych nazw etykiet. .Csma 3 znaki, gdy 1 byłoby w porządku.
Peter Cordes
Potem .att_syntax noprefixprawdopodobnie już się nie zwraca. .intel_syntax noprefixpozwoli ci również upuścić te sześć $prefiksów. ale prawdopodobnie nadal nie warto. (Można użyć lea ecx,.Cszamiast składni 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

Aby go wykonać, wywołaj ::tcl::unsuppoted::assemblekod jako argument.
Tylko Tcl 8.6.

Johannes Kuhn
źródło
3
Powinieneś dołączyć liczbę bajtów.
MD XF
0

80x86 TASM, 561 bajtów

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
MD XF
źródło