Was tut dieser Assembly Code? (Anfängerfrage)



  • 	.file	"main.c"
    	.text
    	.section	.rodata
    .LC0:
    	.string	"The value of x is = %d\n"
    	.text
    	.globl	iterate
    	.type	iterate, @function
    iterate:
    .LFB0:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp
    	.cfi_def_cfa_register 6
    	subq	$16, %rsp
    	movl	$0, -4(%rbp)
    	jmp	.L2
    .L3:
    	movl	-4(%rbp), %eax
    	movl	%eax, %esi
    	leaq	.LC0(%rip), %rdi
    	movl	$0, %eax
    	call	printf@PLT
    	addl	$1, -4(%rbp)
    .L2:
    	cmpl	$14, -4(%rbp)
    	jle	.L3
    	movl	-4(%rbp), %eax
    	leave
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE0:
    	.size	iterate, .-iterate
    	.section	.rodata
    .LC1:
    	.string	"x = %d\n"
    	.text
    	.globl	main
    	.type	main, @function
    main:
    .LFB1:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp
    	.cfi_def_cfa_register 6
    	subq	$16, %rsp
    	movl	%edi, -4(%rbp)
    	movq	%rsi, -16(%rbp)
    	movl	$0, %eax
    	call	iterate
    	movl	%eax, %esi
    	leaq	.LC1(%rip), %rdi
    	movl	$0, %eax
    	call	printf@PLT
    	movl	$0, %eax
    	leave
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE1:
    	.size	main, .-main
    	.ident	"GCC: (Debian 8.3.0-6) 8.3.0"
    	.section	.note.GNU-stack,"",@progbits
    

    Kann mir das jemand Zeile für Zeile erklären? Es sind keine Optimierungen vorhanden.

    Zeile 19 bis 30 ist eine for Schleife, aber was bedeutet pushq, leave, ret, call usw.? Wieso steht nach jedem mov usw. noch ein l? Was ist der Unterschied zwischen : . % und $ ? Könnte man auch selber Assembly Code schreiben, wenn ja wie lernt man solche Muster am besten?



  • also mit push schiebst du daten auf den stack,
    mit call rufst du unterprogramme auf, leave und return werden meine ich beim beenden von unterprogrammen verwendet,
    das l hinter dem mov ruft eine funktion namens movl auf (ja wer hätte das gedacht?), es gibt auch noch movb usw. damit legst du quasi die registerbreite fest.
    % wird vor registernamen gestellt, $ vor konstanten (in zeile 24 wird der wert 0 in das (32 bit) register eax geladen)

    ja man kann auch selbst assemblercode schreiben. das macht man nach meinem wissen z.b. bei der bildverarbeitung, weil man dort die großen register braucht oder mehrere multiplikationen gleichzeitig ausführen will und C oder C++ das nicht so hergeben. bei amazon gibts meine ich ein buch über x64 assembler, ich weiß aber nicht, ob das was taugt. assembler ist jedenfalls immer prozessorspezifisch, d.h. "den assembler" gibt es nicht.



  • @EinNutzer0 sagte in Was tut dieser Assembly Code? (Anfängerfrage):

    Könnte man auch selber Assembly Code schreiben,

    Ja, denn das ist dokumentiert.

    wenn ja wie lernt man solche Muster am besten?

    Das ist eine (Prozessorspezifische) Programmiersprache.
    Die lernt man wie jede andere auch. Dokumentation lesen und üben.



  • Habe eine super Beschreibung/Anleitung gefunden: https://www.complang.tuwien.ac.at/ubvl/amd64/amd64h.html
    ... und so weit kommentiert, wie ich konnte:

    	.file	"main.c"
    	.text
    	.section	.rodata
    .LC0:
    	.string	"The value of x is = %d\n"
    	.text
    	.globl	iterate
    	.type	iterate, @function
    iterate:					# Aufrufstelle für caller
    .LFB0:						# Funktions-Prolog
    	.cfi_startproc
    	pushq	%rbp 				# rbp sichern 
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp			# neuen rbp setzen und rsp sichern
    	.cfi_def_cfa_register 6
    	subq	$16, %rsp			# Platz für lokale Variablen am Stack reservieren 
    	movl	$0, -4(%rbp)			# rbp als lokale Variable i mot 0 speichern 
    	jmp	.L2				# weiter zu .L2
    .L3:
    	movl	-4(%rbp), %eax			# rbp in eax speichern
    	movl	%eax, %esi			# eax in esi speichern
    	leaq	.LC0(%rip), %rdi		# ?
    	movl	$0, %eax			# 0 in eax speichern
    	call	printf@PLT			# Ausgabe-Aufruf
    	addl	$2, -4(%rbp)			# 2 (!!!) zu rbp addieren
    .L2:
    	cmpl	$14, -4(%rbp)			# rbp mit 14 vergleichen
    	jle	.L3				# wenn <= geht es mit der Schleife .L3 weiter
    	movl	-4(%rbp), %eax			# rbp in eax speichern
    	leave					# Activation Record der Funktion entfernen 
    	.cfi_def_cfa 7, 8
    	ret					# Rückkehr von call
    	.cfi_endproc
    .LFE0:
    	.size	iterate, .-iterate
    	.section	.rodata
    .LC1:
    	.string	"x = %d\n"
    	.text
    	.globl	main
    	.type	main, @function
    main:
    .LFB1:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp
    	.cfi_def_cfa_register 6
    	subq	$16, %rsp
    	movl	%edi, -4(%rbp)
    	movq	%rsi, -16(%rbp)
    	movl	$0, %eax
    	call	iterate
    	movl	%eax, %esi
    	leaq	.LC1(%rip), %rdi
    	movl	$0, %eax
    	call	printf@PLT
    	movl	$0, %eax
    	leave
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE1:
    	.size	main, .-main
    	.ident	"GCC: (Debian 8.3.0-6) 8.3.0"
    	.section	.note.GNU-stack,"",@progbits
    

    Zeile 26 habe ich geändert (2), so dass jetzt 16 anstatt 15 ausgegeben wird...
    Könnt ihr noch die anderen Stellen ergänzen?



  • This post is deleted!


  • Muss es x86 bzw. x64 Assembler sein?

    Willst du am Output eines C-Compilers lernen?

    Du kannst auch Funktionen für C in Assembler schreiben.



  • Ich hab früher als Jugendlicher gerne 68000er Assembler programmiert für den Amiga. Das fand ich wesentlich einfacher als meine paar Versuche x86 Asm viele Jahre später.



  • @DirkB sagte in Was tut dieser Assembly Code? (Anfängerfrage):

    Muss es x86 bzw. x64 Assembler sein?

    Ne, ich muss für eine Prüfung den (Inline) Assemblercode eines bestimmten Mikrocontrollers verstehen und anwenden können. Also zum Beispiel eine Schleife mit einer if-else Bedingung programmieren können, über Arrays durchlaufen usw.

    Und dann dachte ich mir, mit irgendetwas musst du ja anfangen (amd64).



  • Sowas zu programmieren ist aber wesentlich einfacher als wenn man den fertigen Code eines C Programms analysiert. Ein Array ist nix weiter als ein zusammenhängender Speicherbereich. Zählen tut man in dem ein Register oder eine Speicherstelle inkremiert oder dekremiert wird, den Wert vergleicht und dann bei bestimmten Flags springt. If Then else sind auch nur bedinge Sprünge also cmp(compare) und danach z.B. bne(branch if not zero, da werden Statusflags der CPU ausgewertet und wenn bei einer Operation vorher das Zeroflag gesetzt wurde, wird gesprungen) Egal wie die jeweiligen Befehle auf dem konkrekten Prozessor aussehen, das Prinzip bleibt gleich.



  • @Wade1234 sagte in Was tut dieser Assembly Code? (Anfängerfrage):

    das l hinter dem mov ruft eine funktion namens movl auf (ja wer hätte das gedacht?), es gibt auch noch movb usw. damit legst du quasi die registerbreite fest.
    % wird vor registernamen gestellt, $ vor konstanten (in zeile 24 wird der wert 0 in das (32 bit) register eax geladen)

    Beachte auch, dass es verschiedene Syntax für assember gibt, also die AT&T und die von Intel (welche ich leichter lesbar finde, weil sie weniger Sonderzeichen hat). Wenn du dem gcc bei -S noch -masm=intel mitgibst, bekommst du die Intel-Syntax.

    Insbesondere gibt es bei Intel nur ein "mov" und die Länge ergibt sich automatisch aus den Operanden, während du hier explizit mov-Long hast. Wenn sich die Länge z.B. bei Pointern nicht automatisch ergibt, musst du sowas wie "word ptr" dazuschreiben. Ach ja, und die Reihenfolge der mov-Zuweisung ist auch umgedreht 🙂 Und sowas wie $ und % brauchst du da auch nicht. Vielleicht wäre das auch für dich, @EinNutzer0, einfacher zu verstehen?

    Ansonsten wäre noch mein Tipp, mit dem Compiler Explorer ein bisschen rumzuspielen und dir Assember für ein paar kleine Funktionen anzugucken. Der CE ist per Default auf Intel-Syntax eingestellt (du kannst da aber den Haken bei Intel ausmachen, wenn du willst).



  • @EinNutzer0 sagte in Was tut dieser Assembly Code? (Anfängerfrage):

    Ne, ich muss für eine Prüfung den (Inline) Assemblercode eines bestimmten Mikrocontrollers verstehen und anwenden können.

    Warum lernst du nicht gleich für den Controller.
    Es gibt einfachere Syntax als x64 Assembler.



  • Ok, Danke für alle Antworten bisher. Noch eine Frage... Wenn ich zum Beispiel diesen C Code habe:

    #include <stdio.h>
    #include <math.h>
    
    int getx(int r, int w)
    {
    	int x;
    	float w2 = w * (M_PI / 180.0);
    	x = (int) (r * cos(w2));
    	return x;
    }
    
    int gety(int r, int w)
    {
    	int x;
    	float w2 = w * (M_PI / 180.0);
    	x = (int) (r * sin(w2));
    	return x;
    }
    
    void get_kreis(int to)
    {
    	int i = 0, x, y, x2, y2;
    	while (i <= to) {
    		x = getx(25, i);
    		y = gety(25, i);
    		if (x != x2 || y != y2) {
    			printf("i=%03d x=%03d y=%03d\n", i, x, y);
    		}
    		x2 = x;
    		y2 = y;
    		i++;
    	}
    	printf("ready.\n");
    }
    
    int main ()
    {
    	get_kreis(720);
    }
    

    wie komme ich dann zu dem nächsten Schritt, dieses Programm manuell in Assembler zu schreiben?

    Der Aufruf gcc -O0 -S -fverbose-asm -o main.S main.c -lm ergibt Folgendes:

    	.file	"main.c"
    # GNU C17 (Debian 8.3.0-6) version 8.3.0 (x86_64-linux-gnu)
    #	compiled by GNU C version 8.3.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.20-GMP
    
    # GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
    # options passed:  -imultiarch x86_64-linux-gnu main.c -mtune=generic
    # -march=x86-64 -auxbase-strip main.S -O0 -fverbose-asm
    # options enabled:  -fPIC -fPIE -faggressive-loop-optimizations
    # -fasynchronous-unwind-tables -fauto-inc-dec -fchkp-check-incomplete-type
    # -fchkp-check-read -fchkp-check-write -fchkp-instrument-calls
    # -fchkp-narrow-bounds -fchkp-optimize -fchkp-store-bounds
    # -fchkp-use-static-bounds -fchkp-use-static-const-bounds
    # -fchkp-use-wrappers -fcommon -fdelete-null-pointer-checks
    # -fdwarf2-cfi-asm -fearly-inlining -feliminate-unused-debug-types
    # -ffp-int-builtin-inexact -ffunction-cse -fgcse-lm -fgnu-runtime
    # -fgnu-unique -fident -finline-atomics -fira-hoist-pressure
    # -fira-share-save-slots -fira-share-spill-slots -fivopts
    # -fkeep-static-consts -fleading-underscore -flifetime-dse
    # -flto-odr-type-merging -fmath-errno -fmerge-debug-strings -fpeephole
    # -fplt -fprefetch-loop-arrays -freg-struct-return
    # -fsched-critical-path-heuristic -fsched-dep-count-heuristic
    # -fsched-group-heuristic -fsched-interblock -fsched-last-insn-heuristic
    # -fsched-rank-heuristic -fsched-spec -fsched-spec-insn-heuristic
    # -fsched-stalled-insns-dep -fschedule-fusion -fsemantic-interposition
    # -fshow-column -fshrink-wrap-separate -fsigned-zeros
    # -fsplit-ivs-in-unroller -fssa-backprop -fstdarg-opt
    # -fstrict-volatile-bitfields -fsync-libcalls -ftrapping-math -ftree-cselim
    # -ftree-forwprop -ftree-loop-if-convert -ftree-loop-im -ftree-loop-ivcanon
    # -ftree-loop-optimize -ftree-parallelize-loops= -ftree-phiprop
    # -ftree-reassoc -ftree-scev-cprop -funit-at-a-time -funwind-tables
    # -fverbose-asm -fzero-initialized-in-bss -m128bit-long-double -m64 -m80387
    # -malign-stringops -mavx256-split-unaligned-load
    # -mavx256-split-unaligned-store -mfancy-math-387 -mfp-ret-in-387 -mfxsr
    # -mglibc -mieee-fp -mlong-double-80 -mmmx -mno-sse4 -mpush-args -mred-zone
    # -msse -msse2 -mstv -mtls-direct-seg-refs -mvzeroupper
    
    	.text
    	.globl	getx
    	.type	getx, @function
    getx:
    .LFB0:
    	.cfi_startproc
    	pushq	%rbp	#
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp	#,
    	.cfi_def_cfa_register 6
    	subq	$32, %rsp	#,
    	movl	%edi, -20(%rbp)	# r, r
    	movl	%esi, -24(%rbp)	# w, w
    # main.c:7: 	float w2 = w * (M_PI / 180.0);
    	cvtsi2sd	-24(%rbp), %xmm1	# w, _1
    	movsd	.LC0(%rip), %xmm0	#, tmp95
    	mulsd	%xmm1, %xmm0	# _1, _2
    # main.c:7: 	float w2 = w * (M_PI / 180.0);
    	cvtsd2ss	%xmm0, %xmm2	# _2, tmp98
    	movss	%xmm2, -4(%rbp)	# tmp98, w2
    # main.c:8: 	x = (int) (r * cos(w2));
    	cvtsi2sd	-20(%rbp), %xmm3	# r, _3
    	movsd	%xmm3, -32(%rbp)	# _3, %sfp
    # main.c:8: 	x = (int) (r * cos(w2));
    	cvtss2sd	-4(%rbp), %xmm0	# w2, _4
    	call	cos@PLT	#
    # main.c:8: 	x = (int) (r * cos(w2));
    	mulsd	-32(%rbp), %xmm0	# %sfp, _6
    # main.c:8: 	x = (int) (r * cos(w2));
    	cvttsd2si	%xmm0, %eax	# _6, tmp96
    	movl	%eax, -8(%rbp)	# tmp96, x
    # main.c:9: 	return x;
    	movl	-8(%rbp), %eax	# x, _11
    # main.c:10: }
    	leave	
    	.cfi_def_cfa 7, 8
    	ret	
    	.cfi_endproc
    .LFE0:
    	.size	getx, .-getx
    	.globl	gety
    	.type	gety, @function
    gety:
    .LFB1:
    	.cfi_startproc
    	pushq	%rbp	#
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp	#,
    	.cfi_def_cfa_register 6
    	subq	$32, %rsp	#,
    	movl	%edi, -20(%rbp)	# r, r
    	movl	%esi, -24(%rbp)	# w, w
    # main.c:15: 	float w2 = w * (M_PI / 180.0);
    	cvtsi2sd	-24(%rbp), %xmm1	# w, _1
    	movsd	.LC0(%rip), %xmm0	#, tmp95
    	mulsd	%xmm1, %xmm0	# _1, _2
    # main.c:15: 	float w2 = w * (M_PI / 180.0);
    	cvtsd2ss	%xmm0, %xmm2	# _2, tmp98
    	movss	%xmm2, -4(%rbp)	# tmp98, w2
    # main.c:16: 	x = (int) (r * sin(w2));
    	cvtsi2sd	-20(%rbp), %xmm3	# r, _3
    	movsd	%xmm3, -32(%rbp)	# _3, %sfp
    # main.c:16: 	x = (int) (r * sin(w2));
    	cvtss2sd	-4(%rbp), %xmm0	# w2, _4
    	call	sin@PLT	#
    # main.c:16: 	x = (int) (r * sin(w2));
    	mulsd	-32(%rbp), %xmm0	# %sfp, _6
    # main.c:16: 	x = (int) (r * sin(w2));
    	cvttsd2si	%xmm0, %eax	# _6, tmp96
    	movl	%eax, -8(%rbp)	# tmp96, x
    # main.c:17: 	return x;
    	movl	-8(%rbp), %eax	# x, _11
    # main.c:18: }
    	leave	
    	.cfi_def_cfa 7, 8
    	ret	
    	.cfi_endproc
    .LFE1:
    	.size	gety, .-gety
    	.section	.rodata
    .LC1:
    	.string	"i=%03d x=%03d y=%03d\n"
    .LC2:
    	.string	"ready."
    	.text
    	.globl	get_kreis
    	.type	get_kreis, @function
    get_kreis:
    .LFB2:
    	.cfi_startproc
    	pushq	%rbp	#
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp	#,
    	.cfi_def_cfa_register 6
    	subq	$48, %rsp	#,
    	movl	%edi, -36(%rbp)	# to, to
    # main.c:22: 	int i = 0, x, y, x2, y2;
    	movl	$0, -4(%rbp)	#, i
    # main.c:23: 	while (i <= to) {
    	jmp	.L6	#
    .L9:
    # main.c:24: 		x = getx(25, i);
    	movl	-4(%rbp), %eax	# i, tmp87
    	movl	%eax, %esi	# tmp87,
    	movl	$25, %edi	#,
    	call	getx	#
    	movl	%eax, -16(%rbp)	# tmp88, x
    # main.c:25: 		y = gety(25, i);
    	movl	-4(%rbp), %eax	# i, tmp89
    	movl	%eax, %esi	# tmp89,
    	movl	$25, %edi	#,
    	call	gety	#
    	movl	%eax, -20(%rbp)	# tmp90, y
    # main.c:26: 		if (x != x2 || y != y2) {
    	movl	-16(%rbp), %eax	# x, tmp91
    	cmpl	-8(%rbp), %eax	# x2, tmp91
    	jne	.L7	#,
    # main.c:26: 		if (x != x2 || y != y2) {
    	movl	-20(%rbp), %eax	# y, tmp92
    	cmpl	-12(%rbp), %eax	# y2, tmp92
    	je	.L8	#,
    .L7:
    # main.c:27: 			printf("i=%03d x=%03d y=%03d\n", i, x, y);
    	movl	-20(%rbp), %ecx	# y, tmp93
    	movl	-16(%rbp), %edx	# x, tmp94
    	movl	-4(%rbp), %eax	# i, tmp95
    	movl	%eax, %esi	# tmp95,
    	leaq	.LC1(%rip), %rdi	#,
    	movl	$0, %eax	#,
    	call	printf@PLT	#
    .L8:
    # main.c:29: 		x2 = x;
    	movl	-16(%rbp), %eax	# x, tmp96
    	movl	%eax, -8(%rbp)	# tmp96, x2
    # main.c:30: 		y2 = y;
    	movl	-20(%rbp), %eax	# y, tmp97
    	movl	%eax, -12(%rbp)	# tmp97, y2
    # main.c:31: 		i++;
    	addl	$1, -4(%rbp)	#, i
    .L6:
    # main.c:23: 	while (i <= to) {
    	movl	-4(%rbp), %eax	# i, tmp98
    	cmpl	-36(%rbp), %eax	# to, tmp98
    	jle	.L9	#,
    # main.c:33: 	printf("ready.\n");
    	leaq	.LC2(%rip), %rdi	#,
    	call	puts@PLT	#
    # main.c:34: }
    	nop	
    	leave	
    	.cfi_def_cfa 7, 8
    	ret	
    	.cfi_endproc
    .LFE2:
    	.size	get_kreis, .-get_kreis
    	.globl	main
    	.type	main, @function
    main:
    .LFB3:
    	.cfi_startproc
    	pushq	%rbp	#
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp	#,
    	.cfi_def_cfa_register 6
    # main.c:38: 	get_kreis(720);
    	movl	$720, %edi	#,
    	call	get_kreis	#
    	movl	$0, %eax	#, _3
    # main.c:39: }
    	popq	%rbp	#
    	.cfi_def_cfa 7, 8
    	ret	
    	.cfi_endproc
    .LFE3:
    	.size	main, .-main
    	.section	.rodata
    	.align 8
    .LC0:
    	.long	2723323193
    	.long	1066524486
    	.ident	"GCC: (Debian 8.3.0-6) 8.3.0"
    	.section	.note.GNU-stack,"",@progbits
    

    Jetzt wird quasi schon beschrieben, was jede Zeile tut. Ich möchte jedoch / muss jedoch auch so ein Programm selber, ohne Hilfe des Compilers in der Prüfung hinbekommen. Kann man das überhaupt lernen?



  • Automatisch generierter Code ist übel zu lesen.

    Da sind viele Register-indirekte Zugriffe drin, die du so eigentlich nicht schreiben wirst.
    Du wirst auch keine fertige Funktion sin oder zur Konvertierung haben.

    Aber ja, man kann das in Assembler schreiben.
    Der sieht dann aber ganz anders aus.



  • Ich versuche mal, das selber hinzubekommen. ... sin und cos (-lm) sind natürlich berechtigte Einwände. Selber werde ich diese Funktionen nicht hin bekommmen...



  • @EinNutzer0 sagte in Was tut dieser Assembly Code? (Anfängerfrage):

    Ich möchte jedoch / muss jedoch auch so ein Programm selber, ohne Hilfe des Compilers in der Prüfung hinbekommen. Kann man das überhaupt lernen?

    Und was für Lehrmaterialien hast du bekommen? Wenn das prüfungsrelevant ist, dann hast du doch bestimmt irgendwas bekommen haben, womit du lernen sollst?! Ein korrektes Assemberprogramm in einer Prüfungssituation zu schreiben, halte ich für relativ schwierig, wenn es über "einfache" Dinge mit "normalen" Register hinausgeht - also z.B. wenn du jetzt auch noch die SSE-Befehle (die xmm-Register) kennen sollst (die Leute scheitern bei Bewerbungsgesprächen schon regelmäßig an einfachen Schleifen - in Hochsprachen!).

    Zu sin und cos: sehr häufig kann man, wenn man den Wertebereich, für den sin/cos aufgerufen werden, kennt, die Funktionen durch eine Taylorexpansion annähern. Wenn zum Beispiel nahe 0, dann sinxx\sin x \approx x



  • @DirkB sagte in Was tut dieser Assembly Code? (Anfängerfrage):

    @EinNutzer0 sagte in Was tut dieser Assembly Code? (Anfängerfrage):

    Ne, ich muss für eine Prüfung den (Inline) Assemblercode eines bestimmten Mikrocontrollers verstehen und anwenden können.

    Warum lernst du nicht gleich für den Controller.
    Es gibt einfachere Syntax als x64 Assembler.

    Das da!!!!!111elf



  • @EinNutzer0 Bei deinem Code würde ich erstmal getx und gety zusammen führen, denn der einzige Unterschied ist dass einmal sin und einmal cos genutzt wird, da ist er einzige Unterschied dass du bei einem 90Grad dazurechnen musst um den richtigen Wert zu erhalten. Ich habe früher nur mit FixedPoint Arithmetik gearbeitet und brauchte daher keine Fließkommazahlen. Für Sin/Cos hatte ich eine Look Up Tabelle, musste den Wert also nicht jedes mal neu berechnen, sondern der Winkel war direkt ein Index in einem Array.

    Wie man das heute macht, weiß ich nicht. Ich kann nur berichten wie ich das damals auf dem Amiga in Assembler gemacht hatte.

    Am besten fängst du einfach mit irgendeinen Assemblerkurs für deinen Microcontroller an. Die Befehle sind simple und Assembler ist viel logischer als C oder C++, denn da hängt es davon ab wie bestimmte Sachen im Standard geregelt sind.

    Tja, wie fängt man dann? Wenn man die Assemblerbefehle kennt, dann versucht man wie die CPU zu denken. Ich brauche einen Wert mit dem ich gleich rechnen will? Dann packe ich das in ein CPU Register. Ich brauche einen Wert für später, dann schreibe ich den direkt in eine Speicherstelle wenn nicht mehr genug Register vorhanden sind. Ich will eine Schleife machen? Ich zähle einen Wert im Register auf null runter und springe dann zu einem Label, ist der Wert noch nicht Null, so springe ich dahin wo mein Wert um eins runtergezählt wird und Teste erneut.

    Dieses Springen ist wohl leider vielen Programmierern von heute fremd. Früher gab es in Basic Goto und Gosub was man dann in Assembler in der Art auch wieder findet.

    Ich hatte große Probleme früher nicht mit Goto und Gosub programmieren zu können, da ich das Konzept von Funktionen nicht kannte. Eine noch größere Hürde war dann die Objekt Orientierte Programmierung, das wollte überhaupt nicht in mein Kopf und auch heute setze ich das nur sehr marginal ein, da ich oft keinen Sinn darin sehe OOP einzusetzen. Ich finde es schrecklich mich durch fremden OOP Code zu wurschteln. Um so mehr abstrahiert wird, umso komplizierter wird es durch zublicken und gute aktuelle Dokumentation habe ich im Arbeitsleben nie erlebt.



  • Also ich weiss nicht, x86 ist für mich nach 68k so ziemlich der einfachste Assembler.



  • Ich fand es damals ziemlich krass, von den 16 Registern auf die wenige vom x86 umzuschwenken. Das war aber alles noch zu 486 Zeiten und mit Code Segment etc. Ich habe das auch nur zwei Wochen probiert und nicht mehr wie so ein Echtzeit Apfelmännchen mit gemacht, dann hatte ich keine Lust mehr auf x86. Bzw dann kam eine kurze Zeit TurboPascal mit Assemblerstücken und irgendwann mal kurz der portable Assembler C. Alles aber nie so intensiv wie damals auf dem Amiga.

    Für mein jetziges Projekt werde ich später auch versuchen einige Teile selbst in Assembler zu optimieren, einfach um mal real zu erleben wer besser ist. Ich oder der Compiler, aber wahrscheinlich wird der Compiler gewinnen.



  • Ok, hier nu mein Versuch, zumindest getx umzuschreiben:

    	.globl	getx
    	.type	getx, @function
    getx:
    .LFB0:
    	push		%ecx
    	push		%edx
    # main.c:7: 	float w2 = w * (M_PI / 180.0);
    # main.c:8: 	x = (int) (r * cos(w2));
    # main.c:9: 	return x;
    	divss		%ecx, $0x4048f5c3, $0x43340000
    	mulss		%edx, %ecx, %ebx
    	movs		%edx, %xmm0
    	call		cos@PLT
    	movs		%xmm0, %edx
    	mulss		%eax, %eax, %edx
    	cvttss2si	%eax, %eax
    	leave
    	ret
    

    Und gleich auch 1000 Fehlermeldungen bezüglich der 32-bit Register:

    main.c: Assembler messages:
    main.c:42: Error: operand type mismatch for `push'
    main.c:43: Error: operand type mismatch for `push'
    main.c:47: Error: number of operands mismatch for `divss'
    main.c:48: Error: number of operands mismatch for `mulss'
    main.c:49: Error: operand type mismatch for `movs'
    main.c:51: Error: operand type mismatch for `movs'
    main.c:52: Error: number of operands mismatch for `mulss'
    main.c:53: Error: operand type mismatch for `cvttss2si'
    

    push gibt es anscheinend für 32-bit nicht und divss und mulss nehmen keine 3 Operanden bei 64-bit. Blöd alles.


Log in to reply