프로세스의 메모리에 대하여..

bw001730의 이미지

운영체제/커널책 이것 저것 사놓구
여러책 참조하면서 공부하고 있습니다.
( 책한권 다읽구 다시 보면 다시 처음처럼 느껴져서
이제는 정리하면서 첨부터 볼려구 시도중입니다.)

프로세스 부분을 정리하다가 제가 가진 의문점이 있는데
제가 가진 책중에는 제대로 정리해 놓은 책이 없었습니다 ㅠㅠ

제 의문점은..

a.out이 메모리로 올라가면서 프로세스의 메모리맵이 구성되겠죠



커널영역
환경변수영역
스택영역
힙영역
데이타영역
코드영역(여기가 0번지)


머 이런식으로 프로세스의 맵이 구성될 것입니다.

한가지 궁금한 점은 공유라이브러리를 호출하는 프로그램이라면
사용하지 않는 시점에 공유라이브러리를 메모리에 로드하지 않을텐데요
따라서 프로세스의 고정된 주소에 맵핑시키지 않을것 같은데요
고정된 주소가 아니라면 동적으로 결정한다는 것인데
.............
(맞나요?)

공유라이브러리가 호출될때 어디로 로드될까요?
(프로세스 메모리의 어느부분에 attach(첨부) 하는가라는 질문이 맞겠죠)

shared memory같은 것도 비슷한 경우일것 같은데요
shmattach()할때 프로세스에 메모리가 첨부될텐데
흠......... 내가 모가 궁금한지도 모르겟네

아직 잘 몰라서 이거 말고도 막연한 궁금증이 많습니다.
첨부되는 위치보다도 그 내부적인 동작이 궁금하군요

이와 관련한 문서라든가 사이트라든가 알려주시면 착하게 살아보겠습니다.
(답답한 마음에 영문이라도 감사하게 볼것 같습니다 ^^;)

정리다되면
사이트에 올리겠습니다. ^^; (누가볼지나 모르겠지만 ㅋ)

익명 사용자의 이미지

운영체제보다 컴퓨터 아키텍쳐 서적을 한번 보시면 답이 나오리라 생각됩니다.

메모리 뿐만아니라 외부 I/O 등등 시스템의 동작 구조를
이해할 수 있게 될 것 같습니다.

약간 시간을 넓게 보고...좀더 하위 단계부터 차근차근하면 2년 정도면....

유닉스, 리눅스의 내부에서 일어나고 있는 일을 몸으로 느끼게 될
때가 올 지도 모르죠.. ^^;

시간이 많으시다면

물리 -> 전기 -> 전자 -> 디지털 회로 -> 컴터구조
-> O/S -> 시스템 소프트웨어 -> 자료구조, DB -> 네트워크, 병렬처리
-> 분산처리, 소프트웨어 공학론

으로 과정을 밟는다면...

컴터 시스템과 자신의 머리가 직접 연결 되어 버린 듯한 착각이 들 날이
올겁니다! 반드시!!!!!

생각만해도 가슴이 뛰는 군요

:oops: :wink:

bw001730의 이미지

저도 가슴이 뛰네요
근데 가슴만 뛰고 머리는 막막..

익명 사용자의 이미지

힙영역과 스택영역 사이의 영역이 아닐까 하는...

kernelpanic의 이미지

저도 어디선가 힙과 스택 사이라고 본 것 같습니다.

익명 사용자의 이미지

이론서를 읽은 분들은 쉽게 이해하실 분도 있을 거고
너무 어렵다고 하실 분도 있을 것 같네요.

UNIX상에서는 Position independent code라는 것을 이용해서
공유라이브러리를 구성하게 됩니다.

프로그램을 실행한다는 말은 로더를 호출해서
프로그램 파일 위치를 알려주는 것인데
공유라이브러리의 경우는
이때 링크를 하게 되겟죠 함수명(심볼)을 주소값으로
연결해 줌을 의미합니다.

http://encyclopedia.thefreedictionary.com/position%20independent%20code

윈도우는 모르겠습니다. -.-;;;;;;;;;;;

그외 실행중에 수동으로도 링크를 할 수도 있군요.

외부 플러그인 같은 기능을 넣을 수 있도록 해주는 프로그램을
만든다면 일단 실행하고 공유 라이브러리를 가지고 올 수 있도록
하는 프로그래밍적인 방법(프로그래밍적인 시스템 인터페이스)을 제공하고 있습니다.

대표적인 예로 아파치웹서버가 있네요

http://httpd.apache.org/docs/dso.html

음... 메모리 위치는 중요치 않습니다.
O/S에 따라 달라지니깐요.

굿이 말하자면 unpredictable입니다. 단 코드 존에 존재하겠죠.

가상메모리에 프로세스의 메모리가 맵핑됨을 생각해보면

높은 번지에서 순서대로
1. 명령문 매개변수, 환경변수
2. 스택
3. 힙
4. 초기화 안된 정적 데이터
5. 초기화 된 정적 데이터
6. 코드

이렇게 잡히게 되니깐..

공유 라이브러리는
코드와 정적 데이터 사이에 로드되고
번지를 제정렬 하게 되지 않을까 싶습니다.

http://encyclopedia.thefreedictionary.com/Dynamic%20link%20library

도 참고해 보시면 DLL에 대해서(윈도우의 .dll 파일이 아니고 용어) 나와 있네요.

글구 공유 메모리 처럼 런타임에 메모리 맹핑만 바뀌는 것이 아니고
첨에 실행될 때 메모리에 로드됨에 주목하시면 좀 이해가 되실 것 같습니다.

bw001730의 이미지

님께서 말씀해주신 덕분에 제가 제 질문을 다시 정리해볼수 있었습니다.
정말 감사합니다.

1. 명령문 매개변수, 환경변수
2. 스택
3. 힙
4. 초기화 안된 정적 데이터
5. 초기화 된 정적 데이터
6. 코드

각 6개의 영역이 있는데요

데이타영역과 코드영역의 사이에 공유라이브러리가 로드된다면 ..
아래와 같이 예를 들어보겠습니다.

코드영역        :  0~100번지
데이타영역     : 100~ 500번지
힙+스택영역   : 500~ 1000번지
나머지 영역    : ...
(모 합쳐도 4G가 안되겠지만 간단히 위와같이 정의해보조)

공유라이브러리함수 호출시
코드영역과 데이타영역 사이에서 로드된다면?

코드영역                    :  0~100번지
방금 로드된 공유라이브러리코드 :  ??? 번지
데이타영역                 : 100~ 500번지
힙+스택영역               : 500~ 1000번지
나머지 영역    : ...

위와 같이 공유라이브러리코드가 위치할 주소가 없게 되잔아요

님께서 말씀하신 것처럼...
만약 공유라이브러리 호출시에 메모리를 재정렬한다면 말이 되겠네요


근데... 메모리 재정렬하는 것이 문제가 안되나 모르겠군요
이미 로드되어 있지 않은 공유라이브러리 호출시마다 메모리 재정렬하게
되는 것이 맞는것인지.......

아...약간 부족한 이 느낌은 소스보면서 공부할 부분이겠죠?
답변 감사드립니다.

익명 사용자의 이미지

실행코드와 스태틱 변수 사이에 먼가 들어간다는 생각은..-.-;; 미틴생각이었습니다.

일단.. 1. shared object는 프로그램 실행시에 메모리에 로드되고 링크된는 점. (호출 할 때가 아닙니다 메모리로 로드될 때 주소가 맵핑 됨) pmap -x명령으로 프로세스의 메모리 멥을 확인해 보면 가장 낮은 주소 부분에 공유 라이브러리가 로드되어 있는 것 처럼 나오더군요. 음.. 아마도 메모리는 하나인데 읽기 전용으로 셋팅되어 있고 실행가능한 부분이라고 셋팅되어서
사용하는 모든 프로세스가 공유하고 있나 봅니다. (실제로는 하나이군요
각각의 프로세스의 가상메모리로 맵핑되는 군요) 공유라이브러리에 들어 있는 스테틱 코드부분은 각 프로세스에 독립적으로 필요한 영역이니깐...
변수 영역은 생성되겠군요.

예를 들어서 쉘 상에서 명령문을 치고 엔터를 치면
fork나 clone 시스템 콜이 발생하고
execute 같은 시스템 함수가 호출되고
이때 실행파일을 메모리로 로드하고
이 실행 코드에서 아직 링크가 안된 코드를 링크가 되고
더 필요한 공유 라이브러리용의 변수 영역도 할당한 다음에
비로소 실행이 시작되겠군요

그리고 아래 사이트를 참고해 보니 힙과 스텍 사이에 쓰지않는 주소 공간이 존재하는 군요.
공유 라이브러리는 그 영역의 둣 부분에 로드된다고 나와 있었습니다.

http://www.princeton.edu/~psg/unix/Solaris/troubleshoot/vm.html

libc.so같은 파일이 여기에 로드된다고 하는데.. pmap으로 확인해 보니... 프로그램의 위치보다도 낮은 주소에 위치해 있으니... 좀 다른 듯 하고..O/S에 따라 다른가 싶기도 하구요..

음.. 암호같은 설명..-.-;; 죄송합니다. 저두 정확하게는 모르겠습니다.

컴퓨터 구조 서적을 참고해서 addressing의 하드웨어적인 방법과
O/S 서적의 position independent code와
reallocation of address와
시스템 프로그래밍의 기계어 코드 생성 예제 를 참고하면 이론적으로는
해답이 나올 듯합니다.

O/S에 따른 실제 구현방법은 해당 사이트들을 참고 해야 하는 듯 합니다.
http://www.tldp.org/LDP/tlk/tlk.html에 리눅스 커널이 어떻게 구현되어 있는지 나와 있군요. 비교적 자세하게 나오는데
조금 읽어 보니 O/S서적에 자세하게 설명이 나오는 내용중의 일부입니다.

커널 소스는 좀 천천이 보는 편이 좋을 듯 싶습니다.
먼저 이론서들을 습득하는 편이 장래적으로 보아 이득이다고 생각합니다.
부디 저같은 허접말고 진정한 고수가 되려면..... 이론서들을 습득하는 편이 훨씬 빠를겁니다. 그럼 일주일만 투자하면 리눅스 커널의 원리는 파악될 겁니다.
문서만 있다면 UNIX나 윈도우의 커널 부분도 금방 파악할 수 있게 될거라고 생각합니다.

-.-;; 괜한 말 꺼냈다가 별루 도움도 안돼고 주절 거리고 말았네요.

그럼 님의 건투를 빕니다.

bw001730의 이미지

아닙니다.
님 답변이 도움이 많이 되었습니다.
감사감사 ^^

익명 사용자의 이미지

제 생각엔 아마도 ...
좀더 공부해보고 알게되면 다시 올리겠습니다만..
미리 예상을 해보자면....(예상일뿐입니다)

동적으로 코드가 로드되기 위해
미리 주소공간을 예약해둘것 같습니다.
4기가의 공간중에 일부분을 예약해두는 것

여기서 예약이라는 것은 미리 메모리를 할당하는 것이 아니고 단지 지정된 주소영역을 단지 동적으로 로드할
라이브러리를 위해 다른 목적으로 사용하지 않을것 같습니다.

왜냐하면 4기가라는 것이 한 프로세스가 사용하기에는
엄청나게 큰 메모리이므로
미리 어떤 영역을 지정해두는 것이 큰 문제가 될것 같지는 않습니다.
만약 그 공간이 부족하게 된다면?
저도 모르겠네요.
리눅스에서 커널모듈이라는 것도 동적으로
코드를 로드시키는 것일텐데요
커널내에서도 동적으로 로드하기 위한
주소공간을 예약해두지 않을까요?

제가 알지도 못하면서 떠드는 이유는
선배님들이 한마디씩 던져주길 바라는 마음에서입니다.

선배님들 한마디씩 던져주시면 감사

override의 이미지

리눅스에서 elf format 의 경우에 한해서 설명해 드리겠습니다 ^^;
(사실 제가 윈도 쪽에는 문외한이라 ㅡ.ㅡ;)

우선 아래는 여러가지로 한 번 덤프 떠본 텍스트입니다.

Quote:

[override@plus5 test]$ cat test2.c
#include <stdio.h>

int main(void){
printf("test~!\n");
return 0;
}

[override@plus5 test]$ gcc test.c

[override@plus5 test]$ ldd ./a.out
libc.so.6 => /lib/tls/libc.so.6 (0x42000000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

[override@plus5 28683]$ cat maps
08048000-08049000 r-xp 00000000 03:03 3589014 /home/override/test/test/a.out
08049000-0804a000 rw-p 00000000 03:03 3589014 /home/override/test/test/a.out
40000000-40015000 r-xp 00000000 03:03 4014088 /lib/ld-2.3.2.so
40015000-40016000 rw-p 00014000 03:03 4014088 /lib/ld-2.3.2.so
40016000-40017000 rw-p 00000000 00:00 0
42000000-4212e000 r-xp 00000000 03:03 491529 /lib/tls/libc-2.3.2.so
4212e000-42131000 rw-p 0012e000 03:03 491529 /lib/tls/libc-2.3.2.so
42131000-42133000 rw-p 00000000 00:00 0
bfffe000-c0000000 rwxp fffff000 00:00 0

우선 ldd를 통해 확인해보면 이 binary는 shared library 로
libc와 loader를 취함을 알 수 있습니다.

이러한 것들은 .dynamic 섹션에 잇는 스트럭쳐 중 DT_NEEDED로 flag된
녀석들이 shared library name의 offset을 가지고 있습니다.
이 정보를 dynamic linker에게 전해줘서 process image에 올릴것이라고
예상합니다.(확신은 못하겠네요 ㅡ.ㅡ )
여기서 DT_NEEDED로 된 것들이 순서대로 매핑되겠지요.

그리고 그 라이브러리가 매핑될 절대주소는 런타임 때 결정될 것입니다.
매핑되는 절대주소가 정해져 있었다면 shared library call 할 때
괜히 plt, got 왔다갔다하며 난리치진 않겠죠 ㅡ.ㅡ

그리고 마지막 것은 gdb로 main에 브레이크 걸고 런 시킨뒤
그 pid로 가서 maps를 들여다 봄으로써 한번 확인해봤는데요.
보시다시피 libc와 ld는 힙에 사이좋게 순서대로 올라가고 있네요.

보다 자세한 내용은 ELF TIS 문서의 dynamic linking 부분과
shared object dependencies 부분을 참고하시기 바랍니다.
특히나 이러한 주제는 해킹 분야에서 바이너리 백도어링 쪽이나
ELF에 관련된 여러 문서들을 보시면 여러모로 도움이 되실거라 생각합니다.

bw001730의 이미지

생각해보니
공유라이브러리는 필요할때 로드하는 것이아닐것 같군요
왜 동적으로 로드될것이라 생각했징 ㅡ.ㅡ

님 답변은 무척 객관적인 자료군요 ^^

제가 처음 올린 질문은
런타임에 로드되는 코드라는 의미로 공유라이브러리를 예를 든 것인데......제가 잘못알고 있었던것 같습니다.

런타임에 로드되는 코드들은 어떤 식으로 프로세스의 메모리에 매핑이 되는 것일까요?

override의 이미지

런타임에 로드되는 코드들?

혹시 dlopen, dlsym 등을 이용해서

function을 로드하는것을 뜻하시나요?

dlopen manpage에 있는 코드로 실험해봤습니다.

Quote:

[override@plus5 test]$ cat foo.c
#include <stdio.h>
#include <dlfcn.h>

int main(int argc, char **argv) {
void *handle;
double (*cosine)(double);
char *error;

handle = dlopen ("libm.so", RTLD_LAZY);
cosine = dlsym(handle, "cos");
printf("cosine : 0x%x\n", cosine);

printf ("%f\n", (*cosine)(2.0));
dlclose(handle);
return 0;
}

[override@plus5 test]$ gcc foo.c -ldl

[override@plus5 test]$ ./a.out
cosine : 0x40036780
-0.416147

[override@plus5 29683]$ cat maps
08048000-08049000 r-xp 00000000 03:03 3589014 /home/override/test/test/a.out
08049000-0804a000 rw-p 00000000 03:03 3589014 /home/override/test/test/a.out
40000000-40015000 r-xp 00000000 03:03 4014088 /lib/ld-2.3.2.so
40015000-40016000 rw-p 00014000 03:03 4014088 /lib/ld-2.3.2.so
40016000-40017000 rw-p 00000000 00:00 0
4002b000-4002d000 r-xp 00000000 03:03 4014099 /lib/libdl-2.3.2.so
4002d000-4002e000 rw-p 00002000 03:03 4014099 /lib/libdl-2.3.2.so
4002e000-4002f000 rw-p 00000000 00:00 0
42000000-4212e000 r-xp 00000000 03:03 491529 /lib/tls/libc-2.3.2.so
4212e000-42131000 rw-p 0012e000 03:03 491529 /lib/tls/libc-2.3.2.so
42131000-42133000 rw-p 00000000 00:00 0
bfffc000-c0000000 rwxp ffffd000 00:00 0

[override@plus5 29683]$ cat maps
08048000-08049000 r-xp 00000000 03:03 3589014 /home/override/test/test/a.out
08049000-0804a000 rw-p 00000000 03:03 3589014 /home/override/test/test/a.out
0804a000-0804b000 rwxp 00000000 00:00 0
40000000-40015000 r-xp 00000000 03:03 4014088 /lib/ld-2.3.2.so
40015000-40016000 rw-p 00014000 03:03 4014088 /lib/ld-2.3.2.so
40016000-40018000 rw-p 00000000 00:00 0
4002b000-4002d000 r-xp 00000000 03:03 4014099 /lib/libdl-2.3.2.so
4002d000-4002e000 rw-p 00002000 03:03 4014099 /lib/libdl-2.3.2.so
4002e000-4002f000 rw-p 00000000 00:00 0
4002f000-40050000 r-xp 00000000 03:03 4014101 /lib/libm-2.3.2.so
40050000-40051000 rw-p 00020000 03:03 4014101 /lib/libm-2.3.2.so
42000000-4212e000 r-xp 00000000 03:03 491529 /lib/tls/libc-2.3.2.so
4212e000-42131000 rw-p 0012e000 03:03 491529 /lib/tls/libc-2.3.2.so
42131000-42133000 rw-p 00000000 00:00 0
bfffc000-c0000000 rwxp ffffd000 00:00 0

첫번째 maps는 dlopen을 하기 전이고 두번째 maps는 libm을 dlopen
한 후의 결과입니다.

kim1158의 이미지

:공유라이브러리는 필요할때 로드하는 것이아닐것 같군요
:왜 동적으로 로드될것이라 생각했징 ㅡ.ㅡ

공유라이브러리는 프로그램 "실행중에 필요에 따라" 로더에 의해 로드되는게 맞습니다.
동적라이브러리는 프로그램 "시작"시에 로더에 의해 로드됩니다.

libc.***.so 파일 .so파일은 동적라이브러리지요.

즉 동적라이브러리는 프로그램 시작시에 그 위치가 정해지게 되겠지요.
초기 질문의 시작은 공유라이브러리이고. 실행중에 동적으로 정해질 메모리 위치에 대한 답은 아직 나오지 않은것으로 보입니다. 좀더 고민하셔야 할듯..

정확히 모르기때문에 질문에 대해서는 더이상 말하지 않겠습니다만.. 다만 말씀드리고 싶은것은 너무 bbs의 답변에 의존해서 답을 유추하시지 말기 바랍니다.
망치를 들면 뾰족한것은 모두 못으로 보인다는 '망치의 오류' 가 있지요.
자신의 아는바에 끼워맞추어서 이해하고 답을 하는것은 상당히 위험합니다. 좀더 객관적인 책과 문서를 보고 정리하심이 어떨까요 ..
검증되지 않은 추측이 난무하는 답변은 혼란과 복잡성을 증가시켜 잘못된 결론을 내릴 위험이있습니다

모든 디지털의 목표는 아날로그.

charsyam의 이미지

윈도우에서는 특정 메모리 번지 이후는 모두 공유 영역으로 설정됩니다. 그래서 공유 라이브러리 즉 DLL 등은 그 번지에 매핑됩니다. 그래서 하나 올라간
공유 라이브러리는 나중에 다시 올릴 필요가 없어지는거죠. 모든 프로세스가
공유를 할 수 있으니깐요. 고운 하루되시길...

=========================
CharSyam ^^ --- 고운 하루
=========================

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.