frage zu einem assembler-befehl

guten abend allerseits. wieder etwas, wo ich nicht weiterkomme und so nicht direkt etwas im netz gefunden habe.
ich habe folgendes einfache programm (aus "buffer-overflows ..." von tobias klein, dpunkt-verlag) mit dem gcc mit der option -S kompiliert, welches eigentlich nur die funktionsweise des stacks erläutern soll:

Code:
void funktion(int a, int b, int c)
{
	int buff1[5];
	char buff2[10];

	buff1[0]='6';
	buff2[0]='A';
	buff2[1]='B';
}

int main(void)
{
	int i=1;
	funktion(1,2,3);
	
	return 0;
}

der gcc in der version 4.0.2 gibt mir nun folgendes:

Code:
	.file	"funk_normal.c"
	.text
.globl funktion
	.type	funktion, @function
funktion:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$32, %esp
	movl	$54, -20(%ebp)
	movb	$65, -30(%ebp)
	movb	$66, -29(%ebp)
	leave
	ret
	.size	funktion, .-funktion
.globl main
	.type	main, @function
main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$24, %esp
	andl	$-16, %esp 
	movl	$0, %eax    
	addl	$15, %eax  
	addl	$15, %eax  
	shrl	$4, %eax    
	sall	$4, %eax    
	subl	%eax, %esp
	movl	$1, -4(%ebp)
	pushl	$3
	pushl	$2
	pushl	$1
	call	funktion
	addl	$12, %esp
	movl	$0, %eax
	leave
	ret
	.size	main, .-main
	.ident	"GCC: (GNU) 4.0.2 20050821 (prerelease) (Debian 4.0.1-6)"
	.section	.note.GNU-stack,"",@progbits

es geht jetzt erstmal insbesondere um main(). die ersten drei zeilen (pushl, movl, subl) sind eigentlich klar, auch wenn ich net verstehe, warum da statt 4 byte für int 24 reserviert werden, aber egal. aber was danach kommt verstehe ich überhaupt nicht. warum wird auf die adresse im esp bitweises and mit -16 gemacht? und dann auch die sachen movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax und sall $4, %eax überhaupt nicht nachvollziehbar irgendwie .. ich meine ich weiß, was die assembler-befehle im einzelnen bedeuten, aber sehe im moment da keinen sinn drin. warum wird das ganze nicht einfach ausgelassen, so dass direkt nach dem reservieren des benötigten speichers in der 3. zeile einfach mit dem kopieren der parameter für die funktion() weitergemacht wird (also hier mit pushl $3)? weiß jemand eine antwort oder evtl. auch ne url, wo auf dieses thema näher eingegangen wird? das wäre klasse. ich danke euch.

grüße,
alpha.
 
ich denk mal das haengt irgendwie mit optimierungsversuchen des compilers zusammen. der cpu takt steigt ja schneller als die bandbreite zum speicher. also macht es sinn ein paar assemblerbefehle (==cpu zyklen) mehr aufzuwenden wenn man damit ein paar speicherzugriffe sparen kann.
allerdings sind die mov's ja gerade speicherzugriffe. keine ahnung was es damit auf sich hat. hab aber was anderes gefunden:

Code:
andl    $-16, %esp
This code "and"s ESP with 0xfffffff0, aligning the stack with the next lowest 16-byte boundary. An examination of Mingw's source code reveals that this may be for SIMD instructions appearing in the "_main" routine, which operate only on aligned addresses. Since our routine doesn't contain SIMD instructions, this line is unnecessary.

http://en.wikibooks.org/wiki/Programming:x86_assembly

gefunden hab ich das indem ich einfach nach der asm code zeile gegooglet hab. probiers bei den anderen mal aus und sag bescheid wenn du deren zweck rausfindest. :)

andere interessant aussehende links:
http://en.wikipedia.org/wiki/Compiler_optimization
http://www.redhat.com/software/gnupro/technical/gnupro_gcc.html
http://gcc.gnu.org/projects/optimize.html

allgemeines zu code optimization:
http://vision.eng.shu.ac.uk/bala/c/c/optimisation/1/optimization.html
http://www.azillionmonkeys.com/qed/optimize.html
 
über int Reservierung kann ich nur sagen, dass hier wohl einige Compileroptimierungen im Spiel sind und eventuell ein Overflow schutz. Am besten solltest Du nochmal compileren, aber eben ohne diese Optimierungen (compiler hilfe beachten, da manche Sachen AFAIK per Default an sind)

das andl -16,esp (ich mag keine AT&T Syntax ;)
sollte wohl den Stack alignen (also ausrichten), denn -16 ist 0xFFFFFFF0
was in Bits etwa 111...(letztes Byte) 11110000 entspricht
dadurch werden bei AND Verknüpfung die letzen 4 Bits auf 0 gesetzt. Also eine Optimierung, allerdings sind mir diese Zeilen auch ein Rätsel (vermutlich hat das was mit serialisierung zu tun):
Code:
movl	$0, %eax    
	addl	$15, %eax  
	addl	$15, %eax  
	shrl	$4, %eax    
	sall	$4, %eax
So wie ich das sehe, kommt hier 16(dezimal) raus
das hätte man auch einfacher haben können in dem man direkt 16 von ESP abzog.
Naja, deshalb traue ich auch keinem Compiler ;)
Werde aber bei Gelegenheit im "Optimization for IA-32"(oder so ähnlich)von Intel blättern.

http://www.buha.info/board/showthread.php?t=45400&highlight=buffer+overflow

ahja, hier hab ich exakt Dein Beispielcode:
http://www.buha.info/board/showthread.php?t=48169&highlight=buffer+overflow

EDIT: hm, habe doch etwas länger beim Schreiben gebraucht. Jedenfalls solltet der zweite Link eine hilfe sein.

EDIT2:
allerdings sind die mov's ja gerade speicherzugriffe
nicht bei festen Zahlen. Nicht umsonst gibts da extra Opcode für MOV Register,Integer
 
vielen dank für euere schnellen antworten. die links helfen mir auf jeden fall schonmal weiter. werde mir das morgen genau ansehen oder besser gesagt heute, aber erstmal ein wenig schlafen :)
dankeschön!

grüße,
alpha.

ps: ist ja echt klasse hier, dass immer irgendjemand da ist, der weiterhilft. kenne ich so in dem maße gar nicht aus anderen board etc. :) in diesem sinne nochmal vielen dank!

edit: wenn ich da mal gänzlich durchblicken sollte, werde ich es natürlich hier entsprechend posten, wenn's interessiert.
 
eben kurz ein zwischenstand: also an optimierung kann es glaube ich nicht liegen, zumindest kommt selbst beim expliziten deaktivieren jeglicher optimierungen genau dasselbe heraus. ich schaue weiter, ob ich noch etwas finde. grundsätzlich hab ich mir gedacht, dass entsprechender gcc-code einigen aufschluss darüber geben müsste, wie es gehandhabt wird, allerdings ist es für mich ein schweres unterfangen mit den sourcen klarzukommen. aber mal schauen, vllt kommt ja noch was bei raus.

interessant ist der in seinem paper von tobias klein diesbezüglich zitierte satz aus der mailing-liste der gcc-entwickler zum thema "zu viel speicher reservieren". wörtlich weiß ich es jetzt nciht mehr, aber sie sagen jedenfalls, dass zu viel speicher zu reservieren kein fehler, sondern lediglich verschwendung ist. was man wohl davon halten soll ...

EDIT: cdw hatte recht, schätze ich. ich hab jetzt nochmal mit dem gcc ein wenig herumgespielt und die acht ersten zeilen (bzw. ohne die allererste) von main() ändern sich entsprechend je nachdem, was man bei -mpreferred-stack-boundary=n für n wählt. möglich sind werte zwischen 2 und 12. nimmt man 2 , so kommt folgendes bei raus:

Code:
main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$4, %esp
	movl	$1, -4(%ebp)
	pushl	$3
	pushl	$2
	pushl	$1
	call	funktion
	addl	$12, %esp
	movl	$0, %eax
	leave
	ret
also im prinzip genau das, was ich - wenn ich es "manuell" gemacht hätte, schreiben würde. quasi die "intuitive" lösung.

mit n=3 kommt das hier:
Code:
main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	andl	$-8, %esp
	movl	$0, %eax
	addl	$15, %eax
	addl	$7, %eax
	shrl	$3, %eax
	sall	$3, %eax
	subl	%eax, %esp
	movl	$1, -4(%ebp)
	pushl	$3
	pushl	$2
	pushl	$1
	call	funktion
	addl	$12, %esp
	movl	$0, %eax
	leave
	ret
......
und letztendlich hat sich hier also herausgestellt, dass per default der wert von n=4 genommen wird, so dass das rauskommt, was ich im ersten posting geschrieben hatte:
Code:
main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$24, %esp
	andl	$-16, %esp
	movl	$0, %eax
	addl	$15, %eax
	addl	$15, %eax
	shrl	$4, %eax
	sall	$4, %eax
	subl	%eax, %esp
	movl	$1, -4(%ebp)
	pushl	$3
	pushl	$2
	pushl	$1
	call	funktion
	addl	$12, %esp
	movl	$0, %eax
	leave
	ret

ich glaube das ist dann nun endgültig geklärt. danke nocheinmal euch beiden.

grüße,
alpha.
 
Zurück
Oben