stack

Mind on alati paelunud, et mis arvuti mälus andmetega juhtub; kus nad mingil ajal on.

Sellele küsimusele on hea vastust otsida C keele ja gdb-ga

Lihtne C kood:
1 #include
2 #include
3
4 int main (void) {
5 int *p1, stack[10];
6 int a = 10;
7 int b = 20;
8
9 p1 = stack;
10
11 *p1 = a;
12
13 p1++;
14 *p1 = b;
15
16 printf("value on top(b) is %d, address %d\n", *p1, p1);
17 *p1 = 0;
18
19 p1--;
20 printf("value on top(a) is %d, address %d\n", *p1, p1);
21 *p1 = 0;
22
23 return 1;
24 }

22:56:10 margusja@IRack> gcc stack.c -o stack -g (-g siis on hea gdb-ga asja uurida)

käivitame:
22:56:10 margusja@IRack>
./stack
value on top(b) is 20, address 1791502060
value on top(a) is 10, address 1791502056
22:56:42 margusja@IRack>


Nagu oleks ja ei ole ka. Minule ei piisa.

Läheme debuggeriga kallale:
22:56:42 margusja@IRack> gdb ./stack
GNU gdb 6.3.50-20050815 (Apple version gdb-1705) (Fri Jul 1 10:50:06 UTC 2011)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries .. done

(gdb)

Vaatame, kuhu paigutada breakbointerid:
(gdb) list
1 #include
2 #include
3
4 int main (void) {
5 int *p1, stack[10];
6 int a = 10;
7 int b = 20;
8
9 p1 = stack;
10
(gdb)
11 *p1 = a;
12
13 p1++;
14 *p1 = b;
15
16 printf("value on top(b) is %d, address %d\n", *p1, p1);
17 *p1 = 0;
18
19 p1--;
20 printf("value on top(a) is %d, address %d\n", *p1, p1);
(gdb)
21 *p1 = 0;
22
23 return 1;
24 }
(gdb)

Seame breakbointerid:
(gdb) b 8
Breakpoint 1 at 0x100000e26: file stack.c, line 8.
(gdb) b 12
Breakpoint 2 at 0x100000e37: file stack.c, line 12.
(gdb) b 15
Breakpoint 3 at 0x100000e55: file stack.c, line 15.
(gdb) b 18
Breakpoint 4 at 0x100000e85: file stack.c, line 18.
(gdb) b 22
Breakpoint 5 at 0x100000ecb: file stack.c, line 22.

Programm käima:
(gdb) r
Starting program: /Users/margusja/Documents/c/stack
Reading symbols for shared libraries +........................ done

Breakpoint 1, main () at stack.c:9
9 p1 = stack;

Vaatame, mis meil siis mälus tegelikult toimub:
(gdb) info locals
p1 = (int *) 0x7fff5fbff708
stack = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
a = 10
b = 20
(gdb)

Ülaltoodud infos on oluline info p1 = (int *) 0x7fff5fbff708 – siin algab meie stack. Hetkel on see tühi.
Laseme programmiga edasi:
(gdb) c
Continuing.

Breakpoint 2, main () at stack.c:13
13 p1++;

Vaatame, mis olukord meie stackis on:
(gdb) info locals
p1 = (int *) 0x7fff5fbff6c8
stack = {10, 0, 0, 0, 0, 0, 0, 0, 0, 0}
a = 10
b = 20
(gdb)

Vaatame, mis toimub aadressil 0x7fff5fbff6c8
(gdb) x/10c 0x7fff5fbff6c8
0x7fff5fbff6c8: 10 '\n' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0 '\0' 0 '\0'
0x7fff5fbff6d0: 0 '\0' 0 '\0'
(gdb)
Kenasti on näha, et meie 10 asub alates aardessilt 0x7fff5fbff6c8 4 ühikut.

Okei, laseme, edasi:
(gdb) c
Continuing.

Breakpoint 3, main () at stack.c:16
16 printf(“value on top(b) is %d, address %d\n”, *p1, p1);
(gdb)

Uurime mälu:
(gdb) info locals
p1 = (int *) 0x7fff5fbff6cc
stack = {10, 20, 0, 0, 0, 0, 0, 0, 0, 0}
a = 10
b = 20
(gdb)

Näeme, et stack (sp) on suurenenud: 0x7fff5fbff6cc
Kui vaadata uuesti stacki stacki algusest:
(gdb) x/10c 0x7fff5fbff6c8
0x7fff5fbff6c8: 10 '\n' 0 '\0' 0 '\0' 0 '\0' 20 '\024' 0 '\0' 0 '\0' 0 '\0'
0x7fff5fbff6d0: 0 '\0' 0 '\0'
(gdb)

Koodist lähtuvalt hakkab nüüd nn stack tühjenema:
(gdb) c
Continuing.
value on top(b) is 20, address 1606416076

Breakpoint 4, main () at stack.c:19
19 p1–;
(gdb) x/10c 0x7fff5fbff6c8
0x7fff5fbff6c8: 10 ‘\n’ 0 ‘\0’ 0 ‘\0’ 0 ‘\0’ 0 ‘\0’ 0 ‘\0’ 0 ‘\0’ 0 ‘\0’
0x7fff5fbff6d0: 0 ‘\0’ 0 ‘\0’
(gdb) c
Continuing.
value on top(a) is 10, address 1606416072

Breakpoint 5, main () at stack.c:23
23 return 1;
(gdb) x/10c 0x7fff5fbff6c8
0x7fff5fbff6c8: 0 ‘\0’ 0 ‘\0’ 0 ‘\0’ 0 ‘\0’ 0 ‘\0’ 0 ‘\0’ 0 ‘\0’ 0 ‘\0’
0x7fff5fbff6d0: 0 ‘\0’ 0 ‘\0’
(gdb) c
Continuing.

Program exited with code 01.

 

Tegu on C baasil stack toimimise näitega, masinkoodi uurides, kordagi tegelikult sp ei liigutata, selleks peaks tegema keeruliseme C koodi, või puhtalt masinkoodis push ja pop käsklusi kasutama, seda ehk edaspidi. Siiski antud näide peaks andma ülevaate mäluosa, mida kutsutakse stack, kasutamisloogikast. Siin väljendus kenasti LIFO (LastIn-FirstOut) järjekord samuti.

syscall table

%eax Name Source %ebx %ecx %edx %esx %edi
1 sys_exit kernel/exit.c int
2 sys_fork arch/i386/kernel/process.c struct pt_regs
3 sys_read fs/read_write.c unsigned int char * size_t
4 sys_write fs/read_write.c unsigned int const char * size_t
5 sys_open fs/open.c const char * int int
6 sys_close fs/open.c unsigned int
7 sys_waitpid kernel/exit.c pid_t unsigned int * int
8 sys_creat fs/open.c const char * int
9 sys_link fs/namei.c const char * const char *
10 sys_unlink fs/namei.c const char *
11 sys_execve arch/i386/kernel/process.c struct pt_regs
12 sys_chdir fs/open.c const char *
13 sys_time kernel/time.c int *
14 sys_mknod fs/namei.c const char * int dev_t
15 sys_chmod fs/open.c const char * mode_t
16 sys_lchown fs/open.c const char * uid_t gid_t
18 sys_stat fs/stat.c char * struct __old_kernel_stat *
19 sys_lseek fs/read_write.c unsigned int off_t unsigned int
20 sys_getpid kernel/sched.c
21 sys_mount fs/super.c char * char * char *
22 sys_oldumount fs/super.c char *
23 sys_setuid kernel/sys.c uid_t
24 sys_getuid kernel/sched.c
25 sys_stime kernel/time.c int *
26 sys_ptrace arch/i386/kernel/ptrace.c long long long long
27 sys_alarm kernel/sched.c unsigned int
28 sys_fstat fs/stat.c unsigned int struct __old_kernel_stat *
29 sys_pause arch/i386/kernel/sys_i386.c
30 sys_utime fs/open.c char * struct utimbuf *
33 sys_access fs/open.c const char * int
34 sys_nice kernel/sched.c int
36 sys_sync fs/buffer.c
37 sys_kill kernel/signal.c int int
38 sys_rename fs/namei.c const char * const char *
39 sys_mkdir fs/namei.c const char * int
40 sys_rmdir fs/namei.c const char *
41 sys_dup fs/fcntl.c unsigned int
42 sys_pipe arch/i386/kernel/sys_i386.c unsigned long *
43 sys_times kernel/sys.c struct tms *
45 sys_brk mm/mmap.c unsigned long
46 sys_setgid kernel/sys.c gid_t
47 sys_getgid kernel/sched.c
48 sys_signal kernel/signal.c int __sighandler_t
49 sys_geteuid kernel/sched.c
50 sys_getegid kernel/sched.c
51 sys_acct kernel/acct.c const char *
52 sys_umount fs/super.c char * int
54 sys_ioctl fs/ioctl.c unsigned int unsigned int unsigned long
55 sys_fcntl fs/fcntl.c unsigned int unsigned int unsigned long
57 sys_setpgid kernel/sys.c pid_t pid_t
59 sys_olduname arch/i386/kernel/sys_i386.c struct oldold_utsname *
60 sys_umask kernel/sys.c int
61 sys_chroot fs/open.c const char *
62 sys_ustat fs/super.c dev_t struct ustat *
63 sys_dup2 fs/fcntl.c unsigned int unsigned int
64 sys_getppid kernel/sched.c
65 sys_getpgrp kernel/sys.c
66 sys_setsid kernel/sys.c
67 sys_sigaction arch/i386/kernel/signal.c int const struct old_sigaction * struct old_sigaction *
68 sys_sgetmask kernel/signal.c
69 sys_ssetmask kernel/signal.c int
70 sys_setreuid kernel/sys.c uid_t uid_t
71 sys_setregid kernel/sys.c gid_t gid_t
72 sys_sigsuspend arch/i386/kernel/signal.c int int old_sigset_t
73 sys_sigpending kernel/signal.c old_sigset_t *
74 sys_sethostname kernel/sys.c char * int
75 sys_setrlimit kernel/sys.c unsigned int struct rlimit *
76 sys_getrlimit kernel/sys.c unsigned int struct rlimit *
77 sys_getrusage kernel/sys.c int struct rusage *
78 sys_gettimeofday kernel/time.c struct timeval * struct timezone *
79 sys_settimeofday kernel/time.c struct timeval * struct timezone *
80 sys_getgroups kernel/sys.c int gid_t *
81 sys_setgroups kernel/sys.c int gid_t *
82 old_select arch/i386/kernel/sys_i386.c struct sel_arg_struct *
83 sys_symlink fs/namei.c const char * const char *
84 sys_lstat fs/stat.c char * struct __old_kernel_stat *
85 sys_readlink fs/stat.c const char * char * int
86 sys_uselib fs/exec.c const char *
87 sys_swapon mm/swapfile.c const char * int
88 sys_reboot kernel/sys.c int int int void *
89 old_readdir fs/readdir.c unsigned int void * unsigned int
90 old_mmap arch/i386/kernel/sys_i386.c struct mmap_arg_struct *
91 sys_munmap mm/mmap.c unsigned long size_t
92 sys_truncate fs/open.c const char * unsigned long
93 sys_ftruncate fs/open.c unsigned int unsigned long
94 sys_fchmod fs/open.c unsigned int mode_t
95 sys_fchown fs/open.c unsigned int uid_t gid_t
96 sys_getpriority kernel/sys.c int int
97 sys_setpriority kernel/sys.c int int int
99 sys_statfs fs/open.c const char * struct statfs *
100 sys_fstatfs fs/open.c unsigned int struct statfs *
101 sys_ioperm arch/i386/kernel/ioport.c unsigned long unsigned long int
102 sys_socketcall net/socket.c int unsigned long *
103 sys_syslog kernel/printk.c int char * int
104 sys_setitimer kernel/itimer.c int struct itimerval * struct itimerval *
105 sys_getitimer kernel/itimer.c int struct itimerval *
106 sys_newstat fs/stat.c char * struct stat *
107 sys_newlstat fs/stat.c char * struct stat *
108 sys_newfstat fs/stat.c unsigned int struct stat *
109 sys_uname arch/i386/kernel/sys_i386.c struct old_utsname *
110 sys_iopl arch/i386/kernel/ioport.c unsigned long
111 sys_vhangup fs/open.c
112 sys_idle arch/i386/kernel/process.c
113 sys_vm86old arch/i386/kernel/vm86.c unsigned long struct vm86plus_struct *
114 sys_wait4 kernel/exit.c pid_t unsigned long * int options struct rusage *
115 sys_swapoff mm/swapfile.c const char *
116 sys_sysinfo kernel/info.c struct sysinfo *
117 sys_ipc (*Note) arch/i386/kernel/sys_i386.c uint int int int void *
118 sys_fsync fs/buffer.c unsigned int
119 sys_sigreturn arch/i386/kernel/signal.c unsigned long
120 sys_clone arch/i386/kernel/process.c struct pt_regs
121 sys_setdomainname kernel/sys.c char * int
122 sys_newuname kernel/sys.c struct new_utsname *
123 sys_modify_ldt arch/i386/kernel/ldt.c int void * unsigned long
124 sys_adjtimex kernel/time.c struct timex *
125 sys_mprotect mm/mprotect.c unsigned long size_t unsigned long
126 sys_sigprocmask kernel/signal.c int old_sigset_t * old_sigset_t *
127 sys_create_module kernel/module.c const char * size_t
128 sys_init_module kernel/module.c const char * struct module *
129 sys_delete_module kernel/module.c const char *
130 sys_get_kernel_syms kernel/module.c struct kernel_sym *
131 sys_quotactl fs/dquot.c int const char * int caddr_t
132 sys_getpgid kernel/sys.c pid_t
133 sys_fchdir fs/open.c unsigned int
134 sys_bdflush fs/buffer.c int long
135 sys_sysfs fs/super.c int unsigned long unsigned long
136 sys_personality kernel/exec_domain.c unsigned long
138 sys_setfsuid kernel/sys.c uid_t
139 sys_setfsgid kernel/sys.c gid_t
140 sys_llseek fs/read_write.c unsigned int unsigned long unsigned long loff_t * unsigned int
141 sys_getdents fs/readdir.c unsigned int void * unsigned int
142 sys_select fs/select.c int fd_set * fd_set * fd_set * struct timeval *
143 sys_flock fs/locks.c unsigned int unsigned int
144 sys_msync mm/filemap.c unsigned long size_t int
145 sys_readv fs/read_write.c unsigned long const struct iovec * unsigned long
146 sys_writev fs/read_write.c unsigned long const struct iovec * unsigned long
147 sys_getsid kernel/sys.c pid_t
148 sys_fdatasync fs/buffer.c unsigned int
149 sys_sysctl kernel/sysctl.c struct __sysctl_args *
150 sys_mlock mm/mlock.c unsigned long size_t
151 sys_munlock mm/mlock.c unsigned long size_t
152 sys_mlockall mm/mlock.c int
153 sys_munlockall mm/mlock.c
154 sys_sched_setparam kernel/sched.c pid_t struct sched_param *
155 sys_sched_getparam kernel/sched.c pid_t struct sched_param *
156 sys_sched_setscheduler kernel/sched.c pid_t int struct sched_param *
157 sys_sched_getscheduler kernel/sched.c pid_t
158 sys_sched_yield kernel/sched.c
159 sys_sched_get_priority_max kernel/sched.c int
160 sys_sched_get_priority_min kernel/sched.c int
161 sys_sched_rr_get_interval kernel/sched.c pid_t struct timespec *
162 sys_nanosleep kernel/sched.c struct timespec * struct timespec *
163 sys_mremap mm/mremap.c unsigned long unsigned long unsigned long unsigned long
164 sys_setresuid kernel/sys.c uid_t uid_t uid_t
165 sys_getresuid kernel/sys.c uid_t * uid_t * uid_t *
166 sys_vm86 arch/i386/kernel/vm86.c struct vm86_struct *
167 sys_query_module kernel/module.c const char * int char * size_t size_t *
168 sys_poll fs/select.c struct pollfd * unsigned int long
169 sys_nfsservctl fs/filesystems.c int void * void *
170 sys_setresgid kernel/sys.c gid_t gid_t gid_t
171 sys_getresgid kernel/sys.c gid_t * gid_t * gid_t *
172 sys_prctl kernel/sys.c int unsigned long unsigned long unsigned long unsigned long
173 sys_rt_sigreturn arch/i386/kernel/signal.c unsigned long
174 sys_rt_sigaction kernel/signal.c int const struct sigaction * struct sigaction * size_t
175 sys_rt_sigprocmask kernel/signal.c int sigset_t * sigset_t * size_t
176 sys_rt_sigpending kernel/signal.c sigset_t * size_t
177 sys_rt_sigtimedwait kernel/signal.c const sigset_t * siginfo_t * const struct timespec * size_t
178 sys_rt_sigqueueinfo kernel/signal.c int int siginfo_t *
179 sys_rt_sigsuspend arch/i386/kernel/signal.c sigset_t * size_t
180 sys_pread fs/read_write.c unsigned int char * size_t loff_t
181 sys_pwrite fs/read_write.c unsigned int const char * size_t loff_t
182 sys_chown fs/open.c const char * uid_t gid_t
183 sys_getcwd fs/dcache.c char * unsigned long
184 sys_capget kernel/capability.c cap_user_header_t cap_user_data_t
185 sys_capset kernel/capability.c cap_user_header_t const cap_user_data_t
186 sys_sigaltstack arch/i386/kernel/signal.c const stack_t * stack_t *
187 sys_sendfile mm/filemap.c int int off_t * size_t
190 sys_vfork arch/i386/kernel/process.c struct pt_regs

Assembler hints

Mõned hindid endale mis ikka ja jälle antud keele harva kasutamise tõttu vahel meelest lähevad.

Tegu on siis GNU assembler (as)


value:
.int 10, 20, 30

...

_start:
movl value, %eax # Liigutab label value esimese väärtuse (10) registrisse eax

...

Pointer

value:
.int 10, 20, 30

...

_start:
movl $value, %eax # Liigutab mäluaadressi kus asub label value registrisse eax


...
movl %eax, %edi # Liigutab eax registri väärtuse registrisse edi
...


...
movl %eax, (%edi) # Liigutab registri eax väärtuse mäluaadressile mis on registris edi
...


...
movl %eax, 4(%edi) # Liigutab registri eax väärtuse (mäluaadressile+4byte) mis on registris edi
...


...
movl (%esi), %eax # Liigutab registril esi asuvalt mäluaadressil oleva data registrisse eax
...

Pure assembler machine code versus using libc

Võtame ühe lihtsa programmijupi mis kuvab teie protsessori nimi.

[margusja@hacking asm]$ ./cpuid2
The processor Vendor ID is 'GenuineIntel'

Lähtekood juhul kui kasutame ainult “system call” meetodeid

#cpuid.s Sample program to extract the processor Vendor ID.section .dataoutput:

.ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n"

.section .text

.globl _start

_start:

movl $0, %eax

cpuid

movl $output, %edi

movl %ebx, 28(%edi)

movl %edx, 32(%edi)

movl %ecx, 36(%edi)

# Display

movl $4, %eax # sys_write

movl $1, %ebx # file descriptor to write. 1 is stdout

movl $output, %ecx # start of the display string

movl $42, %edx # lenght of the display string

int $0x80

# Exit

movl $1, %eax # sys_exit

movl $0, %ebx # exit status

Lähtekood libc kasutamisest

#cpuid2.s View the CPUID Vendor ID string using C library calls.section .dataoutput:

.asciz "The processor Vendor ID is '%s'\n"

.section .bss

.lcomm buffer, 12

.section .text

.globl _start

_start:

movl $0, %eax

cpuid

movl $buffer, %edi

movl %ebx, (%edi)

movl %edx, 4(%edi)

movl %ecx, 8(%edi)

# Prepare printf

pushl $buffer

pushl $output

call printf # print $output using libc printf

addl $8, %esp # Move stack pointer pack

pushl $0 # Exit status

call exit # Exite the program using libc exit

Palju lihtsam. Paadunud assembleri mehed võivad küll nina kirtsutada kuid minu arust annab selline miksimine hea praktika ka C ja C++ osas ning tekitab huvi ka nende keelte vastu.

CPUID

Lihtne assembleris kirjutatud programm mis kuvab masina CPU tootja.
Programm on kompileeritud hetkel 2.6.27.5-117.fc10.i686 jaoks.
cpuid

Source


#cpuid.s Sample program to extract the processor Vendor ID.section .dataoutput:
.ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n".section .text.globl _start
_start:movl $0, %eax
cpuid

movl $output, %edi
movl %ebx, 28(%edi)
movl %edx, 32(%edi)
movl %ecx, 36(%edi)

# Display
movl $4, %eax # sys_write
movl $1, %ebx # file descriptor to write. 1 is stdout
movl $output, %ecx # start of the display string
movl $42, %edx # lenght of the display string
int $0x80

# Exit
movl $1, %eax # sys_exit
movl $0, %ebx # exit status
int $0x80