Assembler: Parameter

Pascal, Basic und andere nicht aufgelistete
Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Assembler: Parameter

Beitrag von Architekt » Sa Nov 08, 2014 1:02 pm

Ich bin gerade leicht am verzweifeln:
Wenn ich Zahlen auf den Stack pushe

Code: Alles auswählen

	pushl	$1337
	pushl	$4223
und dann eine Funktion (also ein Label) aufrufe und dort

Code: Alles auswählen

	movl	8(%ebp), %eax
	movl	%eax, 0(%esp)
	movl	12(%ebp), %eax
	movl	%eax, 4(%esp)
mache, habe ich meine Parameter wieder.

pushe ich jedoch Register oder Offsets anstelle der Zahlen, dann kann ich diese nicht mit dieser Methode wiederbekommen:

Code: Alles auswählen

	pushl	0(%esp) # 23
	pushl	4(%esp) # 42
Beide Parameter sind in der aufgerufenen Funktion in diesem Fall 23, sowohl 0(%esp) als auch 4(%esp), wobei 4(%esp) ja eig. 42 sein sollte.
Was kommt da durcheinander? Darf ich keine Register/Offsets Funktions übergreifend auf den Stack packen?

Nachtrag:
Nur zum besseren Verständnis, wir reden von bspw. solchen Funktionen:

Code: Alles auswählen

.globl	_add
_add:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
# Begin Parameters
	movl	8(%ebp), %eax
	movl	%eax, 0(%esp)
	movl	12(%ebp), %eax
	movl	%eax, 4(%esp)
# End Parameters
# ...
Nachtrag 2:
Ändere ich den Zugriff auf den zweiten Parameter ab, so dass ich als Offset 20 statt 12 benutzt, klappt es (in diesem Fall):

Code: Alles auswählen

movl	20(%ebp), %eax
Warum? :shock:

Edit:
Ups völlig falsches Forum.. Kann das jemand verschieben? :D

nufan
Wiki-Moderator
Beiträge: 2515
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Assembler: Parameter

Beitrag von nufan » Sa Nov 08, 2014 1:45 pm

Architekt hat geschrieben:

Code: Alles auswählen

	movl	8(%ebp), %eax
	movl	%eax, 0(%esp)
	movl	12(%ebp), %eax
	movl	%eax, 4(%esp)
Wie kommst du denn auf deine Offsets 8 und 12?
Wenn du deine Parameter im Stack nochmal drauflegen willst, machst du das so:

Code: Alles auswählen

# as --32 -o out.o pars.S
# ld -m elf_i386 out.o
# ./a.out

.text
.code32
.global _start

_start:
    pushl $1337
    pushl $4223

    movl %esp, %ebp
    subl $8, %esp

    movl 0(%ebp), %eax
    movl %eax, 0(%esp)
    movl 4(%ebp), %eax
    movl %eax, 4(%esp)
Was genau versuchst du denn zu erreichen?
Was für ein System verwendest du?
Wie kompilierst du?

Wenn du für 64-bit kompilierst, scheint die Form wie du Register pushed nicht mehr gültig zu sein:
http://www.x86-64.org/documentation/assembly.html
Architekt hat geschrieben:Edit:
Ups völlig falsches Forum.. Kann das jemand verschieben? :D
Done.

Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Re: Assembler: Parameter

Beitrag von Architekt » Sa Nov 08, 2014 1:57 pm

Ich verwende 32 Bit Gnu Assembler und möchte Variablen als Parameter an eine Funktion übergeben. Diese Funktion soll sie (in diesem Fall) addieren und das Resultat zurückgeben.
8 und 12 als Offset habe ich gelesen und es funktioniert ja auch, solange ich nur Zahlen pushen. Aber für Register und Offsets gilt es nicht mehr.. Und ich weiß nicht warum. :(

Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Re: Assembler: Parameter

Beitrag von Architekt » Sa Nov 08, 2014 4:23 pm

Hier mal ein minimales Beispiel:

Code: Alles auswählen

.text
.globl	_alpha_main
_alpha_main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp

	movl	$42, 0(%esp)
	movl	$23, 4(%esp)

	pushl	0(%esp)
	pushl	4(%esp)
	call	_add
	addl	$8, %esp

	addl	$8, %esp
	popl	%ebp
	ret

.globl	_add
_add:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
# Begin Parameters
	movl	4(%ebp), %eax
	movl	%eax, 0(%esp)
	movl	8(%ebp), %eax
	movl	%eax, 4(%esp)
# End Parameters
	
	# a
	pushl	0(%esp)
	call	_println_int
	addl	$4, %esp

	# b
	pushl	4(%esp)
	call	_println_int
	addl	$4, %esp

	addl	$8, %esp
	popl	%ebp
	ret
Und die "runtime":

Code: Alles auswählen

#include <stdio.h>

void println_int(int num) {
	printf("%d\n", num);
}

extern void alpha_main();

int main() {
	alpha_main();
}
Ich würde 42 und 23 als Ausgabe erwarten, bekomme aber
4200065
42
Ändere ich es wie zuvor auf die offsets 8 und 12 bekomme ich zweimal die 42 als Ausgabe.

nufan
Wiki-Moderator
Beiträge: 2515
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Assembler: Parameter

Beitrag von nufan » Sa Nov 08, 2014 6:01 pm

Architekt hat geschrieben:Ändere ich es wie zuvor auf die offsets 8 und 12 bekomme ich zweimal die 42 als Ausgabe.
Das liegt daran:
Architekt hat geschrieben:

Code: Alles auswählen

pushl   0(%esp)
pushl   4(%esp)
Du legst das oberste Element nochmal oben drauf. pushl korrigiert dein %esp, also greifst du mit 4(%esp) wieder auf das gleiche Element am Stack zu.
Willst du das zweite Element, müsstest du einen Offset von 8 verwenden:

Code: Alles auswählen

pushl   0(%esp)
pushl   8(%esp)
Und in der anderen Reihenfolge:

Code: Alles auswählen

pushl   4(%esp)
pushl   4(%esp)

Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Re: Assembler: Parameter

Beitrag von Architekt » Sa Nov 08, 2014 6:10 pm

Das versteh ich nicht. Inwiefern (und warum) korrigiert pushl mein %esp? o.O

nufan
Wiki-Moderator
Beiträge: 2515
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Assembler: Parameter

Beitrag von nufan » Sa Nov 08, 2014 6:13 pm

Architekt hat geschrieben:Das versteh ich nicht. Inwiefern (und warum) korrigiert pushl mein %esp? o.O
%esp zeigt immer auf das oberste Element auf deinem Stack. Wenn du mit pushl was drauf legst, hast du ein neues oberstes Element und musst %esp entsprechend korrigieren.

Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Re: Assembler: Parameter

Beitrag von Architekt » Sa Nov 08, 2014 6:37 pm

Ah, verstehe. Das macht mein Vorhaben natürlich schwierig.
Ich evaluiere meine Expressions immer so, dass sie in %eax gepackt werden und mein eigentlicher Plan war, dann immer %eax zu pushen. Aber das klappt ja dann nicht, weil ich durch den push jedesmal %esp und damit die Variablen offsets verändere... Wie kann ich das den geschickt anstellen?

Also der bisherige (fehlerhafte) Output sieht so aus:
# Begin VarExpr
movl 0(%esp), %eax
# End VarExpr
pushl %eax
# Begin VarExpr
movl 4(%esp), %eax
# End VarExpr
pushl %eax
call _add
addl $8, %esp
edit:
Anders gefragt: Kann ich auf den Stack etwas drauf packen, ohne push und trotzdem ohne weitere offsets zu reservieren?
Oder gibt es einen eleganten Lösungsweg, um Argumente an eine Funktion zu übergeben?

nufan
Wiki-Moderator
Beiträge: 2515
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Assembler: Parameter

Beitrag von nufan » Sa Nov 08, 2014 6:58 pm

Architekt hat geschrieben:Anders gefragt: Kann ich auf den Stack etwas drauf packen, ohne push und trotzdem ohne weitere offsets zu reservieren?
Naja sicher geht das irgendwie, ich würde das ehrlich gesagt aber lassen. Da kommt ein Offset-Chaos raus.
Architekt hat geschrieben:Oder gibt es einen eleganten Lösungsweg, um Argumente an eine Funktion zu übergeben?
Der übliche Weg ist Parameter mit push auf den Stack zu legen und in der Funktion mit pop wieder runter zu nehmen.

Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Re: Assembler: Parameter

Beitrag von Architekt » Sa Nov 08, 2014 7:02 pm

Was ja in meinem Fall ein Problem ist.
Wenn ich add(a + 2, b + 4) aufrufe (mit a = 0(%esp) und b = 4(%esp)) errechne ich zwei temporäre Werte die in %eax gespeichert werden. Wie soll ich das pushen? Pushe ich beim ersten mal %eax hoch, habe ich beim zweiten mal ein offset Problem, denn b ist nun nicht mehr an Stelle 4 sondern an Stelle 8, was aber meine Expression ja gar nicht wissen kann.
Also entweder ich muss beim jedem Call meinen AST manipulieren (was gar nicht geht) oder ich muss irgendwie einige Offsets freihalten und großzügig Speicher reservieren, damit ich meine Parameter dann wie Variablen behandel... Ist ja großer Mist.

Antworten