EzDoum

찾기
처음으로 | 찾기 | 아카이브 | 글 올리기 | 링크 | 자료실 | 통계 | 연락처 | 자유게시판
이지도움 특집
전체보기
네트워크
TI OMAP35x
TI DaVinci
Analog Blackfin
RobotWar2005
임베디드!
캐쉬의 모든것
메모리 할당 알고리즘
CPU 파이프라이닝
자료구조(Tree)
금융

Login
이름

암호

기억하기


사용자 등록

현재 접속중인 등록 사용자는 0명, 익명 사용자는 4명 입니다.
전체 등록 사용자: 751명

마지막 답장
·libcurl + fuse 조합으로 되는게 많네. (1)
·Linux Ftrace에 관해 (3)
·Android MTP ( Media Transfer Protocol ) (1)
·Lighttpd에 인증을 digest 사용시 IE 오동작 문제? (1)
·Dtrace에 관해 (1)

최근글
·OpenSSL and multi-threads (0)
·ARM 환경에서 OpenCL 사용 (0)
·IoT용 WIFI 모듈 비교 ( MCU ) 클래스 (0)
·Glances - 리눅스 여러 가지 항목을 한 화면에서 모니터링 (0)
·plugin 방식의 로그 분석기 (0)

뜨거운 감자
·나는 인터렉티브한 환경에서 역어셈블 한다. (12)
·GNU REGEX (정규표현식) 프로그래밍 강좌 (7)
·SoCRobotWar 2005 - 신입생 기초 교육자료 (7)
·ASP.NET의 데이터 그리드와 사용자 컨트롤 (7)
·DHTML Editing Control (7)

가장 많이 읽은 글
·[Cache] 2-way Set-Associative 방식이란 무엇일까? (2)
·멀티쓰레드(Pthread) 프로그래밍
·GNU REGEX (정규표현식) 프로그래밍 강좌 (7)
·Sorting Algorithm Animation (2)
·SoCRobotWar 2005 - 신입생 기초 교육자료 (7)

Data, Bss Segment 사이즈 변화
글쓴이: EzDoum 글쓴날: 2002년 08월 24일 오후 02:14





kldp에 올라온 질문인데.. 흥미로운게 있어서 제가 
몇가지 실험후에 답글을 달았습니다.

#include <stdio.h>

int arr_data[1000] = { 0, };
int arr_bss[1000];

int main()
{
        int arr_local1[1000];
        int arr_local2[1000] = { 0, };
        printf("Hello World!\n");

        return 0;
}

위의 소스의 변수들을 각각 추가하면서 size로 실행파일의 각 segment의 
크기를 확인해보았더니,
data segment의 크기는 4*1000 + 16만큼 늘어나구요.
bss segment의 크기는 4*1000 + 8만큼 늘어나구요.
text segment의 크기는 초기화안한 경우에는 변화가 없고,
변수를 초기화하면서 선언하면, 8만큼 늘어납니다.

여기서, 변수크기외에 늘어난 크기(16, 8, 8)는
어떤 정보가 추가되기 때문에 생기는 건가요??

-----------------------------------------------------------------

디어셈블 하는 것은 gdb를 사용해도 되고
objdump란 유틸을 사용해도 됩니다.

그럼 일딴 각각의 상태를 정리를 해보지요..

gcc elf.c -s 하면 어셈블리 코드로 생성 해주기는 하는데
실제적으로 어셈블러가 바이너리 정렬같은 것을 하니까..
그냥 바이너리 상태를 덤프해보는게 정확합니다.

-----------------------------------------------------------------
//#include <stdio.h>

int arr_data[1000] ;
int arr_bss[1000];

int main()
{
        int arr_local1[1000];
        int arr_local2[1000] ;
//        printf("Hello World!\n");

        return 0;
}

gcc elf.c -o elf

objdump -h elf

Sections: elf init 없음                                         
Idx Name          Size      VMA       LMA       File off  Algn  
 11 .text         000000fc  080482f0  080482f0  000002f0  2**4  
                  CONTENTS, ALLOC, LOAD, READONLY, CODE         
 14 .data         0000000c  08049410  08049410  00000410  2**2  
                  CONTENTS, ALLOC, LOAD, DATA                   
 20 .bss          00001f60  08049500  08049500  00000500  2**5  
                  ALLOC                                         

-----------------------------------------------------------------
//#include <stdio.h>

int arr_data[1000] = {0,};
int arr_bss[1000];

int main()
{
        int arr_local1[1000];
        int arr_local2[1000] ={0,} ;
//        printf("Hello World!\n");

        return 0;
}

gcc elf2.c -o elf2

objdump -h elf2

Sections: elf2 init 있음                    
Idx Name          Size      VMA       LMA       File off  Algn
 11 .text         0000010c  080482f0  080482f0  000002f0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE       
 14 .data         00000fc0  08049420  08049420  00000420  2**5
                  CONTENTS, ALLOC, LOAD, DATA                 
 20 .bss          00000fc0  0804a4c0  0804a4c0  000014c0  2**5
                  ALLOC                                       

-----------------------------------------------------------------
elf, elf2의 사이즈 비교
                  elf                      elf2             
Idx Name          Size           Algn      Size             Algn
 11 .text         000000fc(252)  2**4      0000010c(268)    2**4
 14 .data         0000000c(12)   2**2      00000fc0(4032)   2**5
 20 .bss          00001f60(8032) 2**5      00000fc0(4032)   2**5

일딴 main에서 약간의 코드 차이가 나는데
바이너리를 덤프해봤습니다. objdump -s elf
이런식으로 하면되는데...

아래를 보시면 알겠지만,
초기화 루틴 때문에 조금 차이가 있습니다.
즉 elf.c같은 경우엔 스택에 공간을 잡아두고 
	(80483a3:       81 ec 40 1f 00 00       sub    $0x1f40,%esp)
바로 사용을 하지만

elf2.c의 경우엔 elf.c와 같이 스택에 자리를 잡아주고
아래와 같이 클리어해주는 작업을 합니다.

	80483b0:       31 c0                   xor    %eax,%eax            
	80483b2:       fc                      cld
	80483b3:       b9 e8 03 00 00          mov    $0x3e8,%ecx
	80483b8:       f3 ab                   repz stos %eax,%es:(%edi)

레지스터 eax를 0으로 만든다음 
플래그를 리셋하고
ecx에 반복할 횟수 (4000)를 지정하고
eax의 값을 %es:(%edi)에 전송하는 거죠..
repz명령어에 의해서 ecx는 하나씩 줄고,, edi는 하나씩 증가하니까
결과적으로는 스택에 자리잡은 arr_local2가 0으로 클리어 되겠지요..

여기서 한가지 집고 넘어갈 사항이 있는데,
만약에 arr_data를 0이 아닌 특정 다른 데이터로 초기화 한다면
arr_local2[1024] = {1,2,3,4,5,6};
이 내용으 rdata 세그먼트에 저장이 되고
지금처럼 스트링일 0 밀어버리는게 아니라... 
메모리 카피하는 어셈블리가 추가됩니다.

그럼 글로벌에 있는 arr_data는 어떨까요?
이것도 초기화 하는 루틴이 있을까요?
요것은 잘 생각해보면 그럴필요가 없습니다.
arr_data는 글로벌 데이터로., 컴파일 타임때 미리 그 값이 정해져서
바이너리에 있는 내용이 그대로 메모리로 올라가니까
초기화 루틴이 필요 없는것이죠..

그럼 결론적으로 사이즈 차이는 왜 생겼을까요?
바로... 이 초기화 하는 루틴때문에 코드가 더 추가 되었기 때문이죠..
그런데 보기좋게 16이란 값으로 차이가 나는걸까요?
그것은... 세그먼트가 효율적인 접근을 위해서 특정 바이트로 정렬이
되기 때문입니다.
즉 elf2는 000000fc 코드사이즈의 임계를 넘어버려서
다음 임계점인 0000010c까지 사이즈가 증가해 버린것이지요..

이제 그럼 아래표에서 왜 Algn값을 찍었는지 알겠지요?
Idx Name          Size           Algn      Size             Algn
 11 .text         000000fc(252)  2**4      0000010c(268)    2**4
 14 .data         0000000c(12)   2**2      00000fc0(4032)   2**5
 20 .bss          00001f60(8032) 2**5      00000fc0(4032)   2**5

자 아래는 main function의 어셈블리 자료입니다.
 
080483a0 <main>: elf
 80483a0:       55                      push   %ebp
 80483a1:       89 e5                   mov    %esp,%ebp
 80483a3:       81 ec 40 1f 00 00       sub    $0x1f40,%esp
 80483a9:       31 c0                   xor    %eax,%eax
 80483ab:       eb 03                   jmp    80483b0 <main+0x10>
 80483ad:       8d 76 00                lea    0x0(%esi),%esi
 80483b0:       c9                      leave
 80483b1:       c3                      ret
 80483b2:       90                      nop
 80483b3:       90                      nop
 80483b4:       90                      nop
 80483b5:       90                      nop
 80483b6:       90                      nop
 80483b7:       90                      nop
 80483b8:       90                      nop
 80483b9:       90                      nop
 80483ba:       90                      nop
 80483bb:       90                      nop
 80483bc:       90                      nop
 80483bd:       90                      nop
 80483be:       90                      nop
 80483bf:       90                      nop

080483a0 <main>: elf2
 80483a0:       55                      push   %ebp
 80483a1:       89 e5                   mov    %esp,%ebp
 80483a3:       81 ec 40 1f 00 00       sub    $0x1f40,%esp
 80483a9:       57                      push   %edi
 80483aa:       8d bd c0 e0 ff ff       lea    0xffffe0c0(%ebp),%edi
 80483b0:       31 c0                   xor    %eax,%eax
 80483b2:       fc                      cld
 80483b3:       b9 e8 03 00 00          mov    $0x3e8,%ecx
 80483b8:       f3 ab                   repz stos %eax,%es:(%edi)
 80483ba:       31 c0                   xor    %eax,%eax
 80483bc:       eb 02                   jmp    80483c0 <main+0x20>
 80483be:       89 f6                   mov    %esi,%esi
 80483c0:       8b bd bc e0 ff ff       mov    0xffffe0bc(%ebp),%edi
 80483c6:       c9                      leave
 80483c7:       c3                      ret
 80483c8:       90                      nop
 80483c9:       90                      nop
 80483ca:       90                      nop
 80483cb:       90                      nop
 80483cc:       90                      nop
 80483cd:       90                      nop
 80483ce:       90                      nop
 80483cf:       90                      nop
 
 
자 그럼 data는 8이 차이가 난다고 했는데
제가 실험을 해보니까. 저는 20이 차이가 나네요..
음.. 이것 역시 정렬때문입니다.

아래의 덤프내역을 보면, elf는 약간의 데이터 영역이
4바이트 단위로 정렬이 되어서... 12바이트로 존재를 합니다.
하지만,,

elf2의 경우엔 12 + 4000 인데. 이것이 4000을 넘어버러서
다음 임계점은 4032까지 커져버린거죠..(elf2의 데이터 정렬은 2^5)
 
Contents of section .data: elf
 8049410 00000000 2c940408 00000000           ....,.......


Contents of section .data: elf2
 8049420 00000000 f0a30408 00000000 00000000  ................
 8049430 00000000 00000000 00000000 00000000  ................
 8049440 00000000 00000000 00000000 00000000  ................
 8049450 00000000 00000000 00000000 00000000  ................
 8049460 00000000 00000000 00000000 00000000  ................
 8049470 00000000 00000000 00000000 00000000  ................
 8049480 00000000 00000000 00000000 00000000  ................
 8049490 00000000 00000000 00000000 00000000  ................

 ....
 

 804a380 00000000 00000000 00000000 00000000  ................
 804a390 00000000 00000000 00000000 00000000  ................
 804a3a0 00000000 00000000 00000000 00000000  ................
 804a3b0 00000000 00000000 00000000 00000000  ................
 804a3c0 00000000 00000000 00000000 00000000  ................
 804a3d0 00000000 00000000 00000000 00000000  ................

elf2에서 일종의 filler가  어디에 들어갔을까요?
그것을 알아보기 위해서 main에 코드를 약간 추가했습니다,
단 여기서 주의할 사항은 코드가 정렬을 위해서 남겨둔
여분보다 커져버리면 전체 코드가 증가해 버리니
절대값 비교가 안됩니다...

//#include <stdio.h>

int arr_data[1000] = {0,};
int arr_bss[1000];

int main()
{
        int arr_local1[1000];
        int arr_local2[1000] ={0,} ;
        arr_data[0] = 1;
//        printf("Hello World!\n");

        return 0;
}

080483a0 <main>:
 80483a0:       55                      push   %ebp
 80483a1:       89 e5                   mov    %esp,%ebp
 80483a3:       81 ec 40 1f 00 00       sub    $0x1f40,%esp
 80483a9:       57                      push   %edi
 80483aa:       8d bd c0 e0 ff ff       lea    0xffffe0c0(%ebp),%edi
 80483b0:       31 c0                   xor    %eax,%eax
 80483b2:       fc                      cld
 80483b3:       b9 e8 03 00 00          mov    $0x3e8,%ecx
 80483b8:       f3 ab                   repz stos %eax,%es:(%edi)
 80483ba:       c7 05 40 94 04 08 01    movl   $0x1,0x8049440
 80483c1:       00 00 00
 80483c4:       31 c0                   xor    %eax,%eax
 80483c6:       eb 00                   jmp    80483c8 <main+0x28>
 80483c8:       8b bd bc e0 ff ff       mov    0xffffe0bc(%ebp),%edi
 80483ce:       c9                      leave
 80483cf:       c3                      ret

자.. 답이 나왔네요.

 80483ba:       c7 05 40 94 04 08 01    movl   $0x1,0x8049440
 
보시면 알겠지만. elf때 있던 12바이트 뒤를 20바이트 0으로 깔고
그다음 부터 0x8049440주욱 연속된 공간을 할당하게 됩니다.

 
제 실험에서는 bss는 제가 원하는 크기 만큼 동일한 사이즈로 줄었네요..

음... 보시고 다시 잘 이해가 안되면 질문해주세요..
덕분에... 저도 옛날에 배운거 복습도 하고 정리도 하고 좋네요. ^^

ps. 
아 한가지 추가.. 자료가 커졌을때 32로 정렬하는것은 무엇 때문일까요? 
ㅋㅋ 

그건 아마도 캐쉬랑 연관이 클껍니다. 
제가 gcc소스를 분석해 보지는 않았지만.. 
제가 컴파일한 환경의 cpu는 다음과 같은 캐쉬라인을 가지고 있거든요 

TLB and cache info: 
01: Instruction TLB: 4KB pages, 4-way set assoc, 32 entries 
02: Instruction TLB: 4MB pages, 4-way set assoc, 2 entries 
03: Data TLB: 4KB pages, 4-way set assoc, 64 entries 
43: 2nd-level cache: 512KB, 4-way set assoc, 32 byte line size 
08: 1st-level instruction cache: 16KB, 4-way set assoc, 32 byte line size 
04: Data TLB: 4MB pages, 4-way set assoc, 8 entries 
0c: 1st-level data cache: 16KB, 4-way set assoc, 32 byte line size 

그래서 캐쉬라인에 걸치지 말라고 저렇게 해주는거 같네요..


  • 관련 링크
  • [분류: 어셈블리 인쇄용 페이지 본문 email로 보내기 ]

    <  C++ Optimization Strategies and Techniques -Pete Isensee | delete date or delete [] data  >

    답장 쓰기
    글을 올리시려면 로그인 (사용자 등록) 하셔야 합니다.

    검색
    Google

    분류
    ·공지 (6)
    ·인터넷 (87)
    ·하드웨어 (260)
    ·C/C++ (65)
    ·어셈블리 (7)
    ·리눅스 (136)
    ·리눅스 커널 (67)
    ·윈도우즈 (25)
    ·데이터베이스 (20)
    ·보안 (16)
    ·.NET (25)
    ·그래픽 (13)
    ·책소개 (42)
    ·호기심 천국 (80)
    ·잡담 (111)
    ·사랑 (3)

    전체 본문수: 963
    전체 답장수: 525


    분류 : 어셈블리
    최근글
    최근글
    가장 많이 읽은 글
    ·나는 인터렉티브한 환경에서 역어셈블 한다. (12)
    뜨거운 감자
    ·나는 인터렉티브한 환경에서 역어셈블 한다. (12)

    EzDoum투표
    이지도움 어때요?
    이게 뭐야. 다시 안올란다. --;
    아이 좋아라~ +_+;
    관심없다.
    먼가는 있는거 같은데 뭐하는 곳이지?
    기타 (자유게시판에 글로 남겨 주세요)
    [ 결과 | 투표 ]

    랜덤 링크
    http://kldp.net


     Home ^ BACK TO TOP ^ EzDoum - 도움이 필요하세요~??
     Powered by KorWeblog 1.5.8 Copyleft © 2001 EzDoum, 관리자: EzDoum