[완료] Critical Section을 nasm코드로 작성해서 호출해보았습니다...그런데...

revival4u의 이미지

NASM CODE:

ch_enter_critical_section:
        pushfd
        cli
        ret
 
ch_exit_critical_section:
        popfd
        ret

C CODE:

int function(void)
{
    ch_enter_critical_section();
        /*do something*/
    ch_exit_critical_section();
}

이렇게 하니깐 kernel panic상태가 되는군요...

혹시나 해서 pushfd, popfd를 제거하니깐 panic 상태로 빠지지는 않더군요...

그렇다는것은 분명 pushfd와 popfd로 인해 esp 값이 변해서 이런결과가 나오게 되었따는것인데...

C와 asm사이에 함수호출시 스텍포인터의 값이 변하게되는 원인이 무엇인지 아시는분 계신가요??

익명 사용자의 이미지

pushfd로 EFLAGS를 stack에 push한 다음 ret를 하면 당연히 이상한 주소로 점프를 하게 되죠.

ret는 풀어서 쓰면

pop temp_register
mov eip, temp_register

입니다. 즉, 이전에 push된 32비트 값을 EIP에 할당하는 명령입니다. 그리고 popfd와 ret 조합
역시 같은 이유로 문제를 발생시킵니다.

차라리 inline assembly에 macro 치환으로 하는 편이 더 나을 것 같습니다.
(일단 커널 코드에서 CLI를 아무 때나 쓸 수 있는가에 대한 문제는 생각하지 않더라도요)

cppig1995의 이미지

ret 명령은 윗 익명분의 말씀처럼, 이전에 push된 것을 인스트럭션 포인터로 넣는 것이고,
pushfd(Push Flag Double-word) 명령으로 eFLAGS를 넣으면 ret을 했을 때 eFLAGS의 주소로 가겠죠.
이는 매우 어처구니없는 결과를 낳게 될 것입니다.

ret을 하기 전에 mov eax, [esp+4]를 해서 eax에 원래 반환할 주소값을 얻은 후 push eax 후 ret을 해줘야 할 것입니다.



It's High Noon...

Real programmers /* don't */ comment their code.
If it was hard to write, it should be /* hard to */ read.

revival4u의 이미지

감사합니다..

추가적인 질문을 하자면...

ret와 iret의 차이점이 정확히 무엇인지 ...

혹시 알려주실수 있나요?

좋은 하루 되세요~

Necromancer의 이미지

ret의 경우 near call에 대응되는 ret와 far call에 대응되는 ret가 있죠.
(far call에 대응되는 ret는 retf라고 쓸겁니다)

near call은 eip만을 stack으로 push하죠. 그때문에 near ret는 eip만 복구합니다.
far call은 eip뿐만 아니라 cs도 push됩니다. 그래서 far ret는 eip와 cs 복구하죠.

그리고 iret는 interrupt에서 빠져나올 때 쓰는건데...
cpu가 interrupt받아서 핸들러 루틴으로 넘어갈때는 cs, eip에 eflags까지 push합니다. 그것까지 복구하는데 iret입니다.

그리고 16비트면 앞에 e자 빠집니다. (cs, ip, flags)

Written By the Black Knight of Destruction

Written By the Black Knight of Destruction

sliver의 이미지

참고로 인터럽트가 발생하여 인터럽트 핸들러 진입으로 인해 CPL이 바뀌어 졌었다면 (예를 들면, CPL 3에서 수행중에 인터럽트가 발생하여 RPL 0인 CS(코드 세그먼트)로 진입하였다면 CPL이 3에서 0으로 바뀌게 되죠),
iret은 SS와 ESP 또한 스택에서 꺼내갑니다.
(오래 돼서 확실친 않은데, 아마 인터럽트가 발생해서 CPL이 바뀌어 질 경우 아마 스택에 인터럽트 발생 당시의 SS와 ESP가 저장되는 것으로 알고 있습니다.
따라서 이 경우 iret은 저장됐던 SS와 ESP들을 스택에서 다시 꺼내어 복구하는 거죠...)

익명 사용자의 이미지

iret은 interrupt 상태에서 ret하는 것입니다. 차이가 있다면 되돌아갈 주소와 함께 EFLAGS가
스택에 함께 저장되어 있다는 정도입니다.

sliver의 이미지

이런 식으로 critical section 보호 코드를 짜면,
enter 당시와 exit 당시의 stack 포인터가 같은 값을 가져야 하므로 아래와 같은 코드의 경우 동작이 제대로 안될듯 합니다.

int function(void)
{
    ch_enter_critical_section();
    while(...) {
        int x; /* 새로운 block안에 변수를 정의할 경우 스택 포인터 값이 변경될 가능성 있음 */
        ch_exit_critical_section();
        ....;
        ch_enter_critical_section();
    }
    ch_exit_critical_section();
}

위 패턴은 보통 mutex와 condition variable을 사용할 경우 흔히 보이는 패턴이죠.

스택에 eflags값을 저장하지 마시고 리눅스 커널에서 따르는 방식대로 ch_enter/exit_critical_section caller가 건내주는 변수에 eflags를
저장하는 방식으로 하시는게 더 안전할 것 같습니다.

revival4u의 이미지

ch_enter_critical_section:
 
        push    eax 
 
        leaxf   ;load eflag to eax
        mov     dword [flag_tmp], eax 
        cli
 
        pop     eax 
        ret
 
ch_exit_critical_section:
 
        push    eax 
 
        mov     eax, dword [flag_tmp]
        seaxf   ;store eflag from eax
 
        pop     eax 
        ret
 
flag_tmp:
        dd  0

위와같이 수정하였습니다.

이렇게 하면 sliver님께서 말씀하신 문제도 해결이 되는군요~

물론 inline assembly로 작성하는것이 더 효율적일거라고 추측하고있지만..

leaxf, seaxf를 사용해서 push와 pop단계를 좀더 줄여 보았습니다.

Necromancer의 이미지

critical section 사용시에는 mov 앞에 lock 명령어도 추가해 주시는 것이 좋습니다.
단일프로세서에서는 lock 안써도 상관없지만(프로세서가 한개라 한 메모리 주소를 동시에 접근하는 일 없음),
멀티프로세서에서 lock 안쓸 경우 여러 프로세서가 한 메모리 주소를 동시에 액세스하는 일이 벌어질 경우 문제가 발생하죠.

lock을 쓰면 mov 등의 명령어로 메모리 접근시 그 메모리 주소를 다른 프로세서에서 접근못하게 막습니다.
궁금하시면 인텔 프로세서 매뉴얼 찾아보시길.

Written By the Black Knight of Destruction

Written By the Black Knight of Destruction

sliver의 이미지

mov에 lock prefix를 붙이는 것은 illegal instruction이 됩니다.
보통 lock prefix는 read, modify, write sequence를 따르는 명령어 앞에만 (예를 들면 inc) 붙일 수 있습니다.
자세한 건 x86 메뉴얼을 참조하세요..

Necromancer의 이미지

제가 잘못 알고 있었군요.
add, adc, and, btc, btr, bts, cmpxchg, dec, inc, neg not, or, sbb, sub, xor, xadd, xchg에만 쓸 수 있다고 나와있네요.

Written By the Black Knight of Destruction

Written By the Black Knight of Destruction

revival4u의 이미지

Necromancer님께서 말씀해 주셔서

lock에대해서도 알게 되었네요..감사합니다(sliver님께도...ㅋㅋ)

lock prefix 사용법은

lock    add   eax, 4

이런식으로 하면되는건가요??

mov앞에 해봤는데... 워닝이나 에러가 나지는 않더군요..

그리고 lock은 process(sofeware)랑은 상관없고 processor(hardware)와 관계가 있다는 물씀이신지...

궁금하네요... 즉 요즘과같은 듀얼 쿼드코어 등등의 architecture에서 lock prefix를 사용하면 유용하다는 말씀 맞나요?

sliver의 이미지

lock prefix는 해당 명령을 수행하는 도중 해당 프로세서 이외에 다른 프로세서가 메모리 접근을 할 수 없도록 막는 역할을 합니다.
위와 같이 레지스터만을 접근할 때는 전혀 필요가 없습니다(필요없는건 확실한데 사용해서는 안되는지는 잘 모르겠습니다).
lock prefix는 항상 유용하기 보다는 여러 프로세서가 동일한 메모리변수를 동시에 read-modify-write할 가능성이 있을 때 동기화를 위해서 사용합니다.
그리고 이렇게 단순한 increment, decrement 정도에만 lock prefix를 통한 동기화를 사용하지,
좀 복잡해지면 spin lock이나 mutex를 사용하게 됩니다.

듀얼코어나 쿼드코어 아키텍쳐에서, 하나의 코어가 메모리 read-modify-write를 하는 도중에 다른 코어가 메모리 접근을 할 수 있는지 여부는 잘 모르겠습니다.
만약 그렇지 않다면, lock prefix는 필요가 없겠으나,
보통 (제가 알기론) SMP를 위한 메모리 동기화나 멀티코어를 위한 메모리 동기화를 서로 구별하지 않고 코드를 작성하기 때문에 lock prefix에 관한 내용이
멀티코어에도 똑같이 해당된다고 생각하는게 안전할 것 같습니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.