C – продължение
by Vasil KolevКато продължение на предишния постинг, едно обяснение на цялата ситуация, понеже изглежда има нужда :)
Та, пак трите фрагмента:
Фрагмент 1:
char *pesho="pesho";
Фрагмент 2:
char *pesho=(char *) malloc (6); strcpy(pesho,"pesho");
Фрагмент 3:
char pesho[6]="pesho";
Първият фрагмент записва низа в секцията .rodata (преди изпълнимия код на програмата) и насочва указателя натам. По принцип там не може да се пише (освен ако не работите под DOS или нещо подобно, което няма защита на паметта), но може да се предава напред-назад като указател.
Вторият фрагмент заделя памет в heap-а и записва в нея string-а. Указателя може да се предава навсякъде, там може да се пише и т.н..
Третия фрагмент е има два под-случая: ако pesho е глобална или локална променлива. В първия случай паметта се заделя в .globl секцията, където се пишат глобалните символи с имената им, за да може динамичния linker да се ориентира кое къде е – този може да се предава навсякъде като аргумент на функция, може да се пише отгоре му и т.н.. Втория случай е локален за функцията, заделя памет в stack-а и записва в него стойността. Указател към това може да се предава към функциите, които текущата вика, но не и на функцията, която е извикала настоящата (понеже при излизането от функцията тая памет вече се de-alloc-ва).
Който иска да види как точно стават нещата, може да си напише нещата в една програмка и да я компилира до асемблер с
gcc -Wall -o pesho.s -S pesho.c
и да разгледа pesho.s, там си личи най-добре.
Нещата са тествани на няколко unix-а (32 и 64битови) и на 32битово Visual C++.
Tags: работа
January 15th, 2008 at 22:40
Дискусията ми напомня за начините за промяна на стойността на числените константи (!!) във FORTRAN от времената преди защитата на паметта, напр.
SUBROUTINE FOO(A,B,C)
INTEGER A,B,C
C=A*B
END
SUBROUTINE BAR(BAZ)
INTEGER BAZ
PRINT *,BAZ
END
…
CALL FOO(2,3,5)
CALL BAR(5)
При липса на защита на паметта, последната програма печата щастливо:
6
Причината е, че всички аргументи във FORTRAN се подават по адрес.
January 15th, 2008 at 22:55
Физика, можеш ли това да го докараш до асемблер, страшно ми е интересно как точно изглежда, па не съм сигурен, че мога да сглобя както трябва цялата fortran програма…
January 15th, 2008 at 23:44
Константите:
.section .rodata
.LC3:
.align 4
.LC0:
.long 5
.align 4
.LC1:
.long 3
.align 4
.LC2:
.long 2
Първото извикване:
movl $.LC0, %edx
movl $.LC1, %esi
movl $.LC2, %edi
movl $0, %eax
call foo_
Второто извикване:
movl $.LC0, %edi
movl $0, %eax
call bar_
Естествено, програмата дава Segmentation fault, но сега ще си поиграя с ELF-а и ще направя .rodata секцията RW ;)
January 16th, 2008 at 00:19
След консултация с readelf и /usr/include/elf.h, с помощта на шестнадесетичния редактор на Midnight Commander вдигам W флаговете за секция .rodata и сегмента, който я съдържа (DOS compatibility mode ;)):
[hristo@node001 ~]$ ./change5
6
Преди това:
[hristo@node001 ~]$ ./change5
Segmentation fault
January 16th, 2008 at 01:01
Това е по-скоро бъг на компилатора, трябва да пази ‘5’ на няколко места (или изобщо да не дава да се правят подобни изпълнения), ужасно странно изглежда и може да доведе до наистина невероятни изпълнения (ако няма защита на паметта :) ).
Би било адски смешно навсякъде вместо 5 да е 6 :)
January 16th, 2008 at 04:39
Пропаднал физик, ти си ненормален :)
January 16th, 2008 at 11:45
Добре казано. Определено има нужда – човек така се пристрастява към езици с “боклукчия”…
January 16th, 2008 at 11:57
Поведението на фортран-а е нормално, той създава 5 като константа, и понеже всички предавания са по reference е възможно да запишеш на адреса на константата друга стойност. Не създава много 5-ци поради това , че не ги предава по стойност, трябва да ги преалокира, и така пести адреси в паметта
January 16th, 2008 at 14:07
Леко лирично отклонение
January 16th, 2008 at 15:21
Абе щом е “pesho”, много ясно, че ще работи ;-)
January 16th, 2008 at 17:55
eto kak izglezhdat neshtata na druga arhitektura:
primordium 106% cat t.c
#include <stdio.h>
char *p = “asdf”;
int main() {
p[0] = ‘t’;
return 0;
}
primordium 107% cc t.c
primordium 108% dbx a.out
dbx version 7.3 MR 55458_Apr30_MR Apr 30 1999 13:44:41
dbx Warning: Unknown processor type 0xe, assuming this is not an R8000
Executable /usr/people/nasko/a.out
(dbx) run
Process 13592 (a.out) started
Process 13592: region 3 identical to prev ignored
Process 13592 (a.out) stopped on signal SIGSEGV: Segmentation violation (default) at [main:6 +0xc,0x10000ce8]
6 p[0] = ‘t’;
(dbx) quit
primordium 109% cc -version
MIPSpro Compilers: Version 7.3.1.3m
primordium 110% uname -aR
IRIX64 primordium 6.5 6.5.29f 01090133 IP30
primordium 111%
asemblera e na http://SIGBUS.PVTRIDVS.NET/pool/tmp/t.s
кирливица
January 16th, 2008 at 18:32
В светлината на всичко по-горе, изненада от страна на DEC:
# cat t.c
#include
char *p = “asdf”;
int main() {
p[0] = ‘t’;
printf(“%s\n”, p);
return 0;
}
# cc t.c
# ./a.out
tsdf
# cc -V
DEC C V5.2-030 on Digital UNIX V4.0 (Rev. 464)
… (200 реда с версиите на всички компоненти) …
# uname -a
OSF1 flamingo V4.0 464 alpha
По подразбиране cc на DEC компилира с опция -writable_strings
January 21st, 2008 at 22:49
мазохисти ! маскари ! мискини ! михлюзи ! мърди !
хората се опитват да ви лекуват с дотНЕТ, Жаби и други разни …
май наистина Керниган/Ричи са написали Цъ-то за да му е гадно на човекя …