Próbuję zrozumieć kod zespołu funkcji C. Nie mogłem zrozumieć, dlaczego andl -16
jest wykonywane na głównym. Czy służy do alokowania przestrzeni dla zmiennych lokalnych. Jeśli tak, dlaczego subl 32
jest wykonane dla głównej.kod zespołu funkcji c
Nie mogłem zrozumieć dezasemblacji func1
. W miarę czytania stos rośnie z adresu wyższego rzędu do niskiego rzędu dla procesorów 8086. A więc tutaj, dlaczego jest dostęp do pozytywnej strony ebp (dla offsetów parametrów) i dlaczego nie w negatywnej stronie ebp. Zmienne lokalne wewnątrz func1 to 3 + adres zwrotny + zapisane rejestry - więc musi być 20, ale dlaczego jest 24? (subl $24,esp
) Kod
#include<stdio.h>
int add(int a, int b){
int res = 0;
res = a + b;
return res;
}
int func1(int a){
int s1,s2,s3;
s1 = add(a,a);
s2 = add(s1,a);
s3 = add(s1,s2);
return s3;
}
int main(){
int a,b;
a = 1;b = 2;
b = func1(a);
printf("\n a : %d b : %d \n",a,b);
return 0;
}
montaż:
.file "sample.c"
.text
.globl add
.type add, @function
add:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $0, -4(%ebp)
movl 12(%ebp), %eax
movl 8(%ebp), %edx
leal (%edx,%eax), %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
leave
ret
.size add, .-add
.globl func1
.type func1, @function
func1:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl 8(%ebp), %eax
movl %eax, 4(%esp)
movl 8(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -4(%ebp)
movl 8(%ebp), %eax
movl %eax, 4(%esp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
movl %eax, 4(%esp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -12(%ebp)
movl -12(%ebp), %eax
leave
ret
.size func1, .-func1
.section .rodata
.LC0:
.string "\n a : %d b : %d \n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $1, 28(%esp)
movl $2, 24(%esp)
movl 28(%esp), %eax
movl %eax, (%esp)
call func1
movl %eax, 24(%esp)
movl $.LC0, %eax
movl 24(%esp), %edx
movl %edx, 8(%esp)
movl 28(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",@progbits
Ten cytat z podręcznika gcc mogą być pomocne: -mpreferred-stosu granica = NUM próbują utrzymać granicę stosu wyrównany do 2 podniesione do num granica bajtów. Jeśli -preferred-border-stack nie jest określony, domyślnie jest to 4 (16 bajtów lub 128 bitów). – teppic
Dziękujemy za wyedukowanie 8-bajtowego wyrównania. Moje wątpliwości są w dodatku -> 1 (zmienna lokalna) + adres zwrotny => 2 * 8 = 16, która jest prawidłowa. Ale w func1 -> 3 (zmienne lokalne) + adres zwrotny => 4 * 8 = 32 powinno tam być. dlaczego jest 24. dlaczego w głównym subl 32 jest zrobione dla wskaźnika bazowego. Jestem trochę zmieszany z wykonanymi obliczeniami. – Angus
@Angus: Przy obliczaniu rozmiaru 'func1', dlaczego mnożysz przez 8? W tej 32-bitowej architekturze obiekty 'int' w' func1' i adresie mają po cztery bajty. 'func1' używa czterech bajtów dla s1, czterech bajtów dla s2, czterech bajtów dla s3, ośmiu bajtów dwa przechodzą dwa parametry do' add' i cztery dodatkowe bajty do pad dla wyrównania. To jest 24 bajty. –