[완료]어셈블리에서 C변수 사용이 가능한가요?

zzang9sds의 이미지

아래 소스는 /arch/arm/kernel/entry-header.S 소스부분이며,
ARM 리눅스에서 시스템콜 후 유저컨텍스트를 복구하는 어셈블리 코드입니다.
위와 같은 어셈블리 코드에서 C변수 사용이 가능한가요?
제가 하고자 하는 작업이 PC값을 C변수에 넣고자 합니다.
도움부탁드리겠습니다( _ _ )ㄱ


.macro  restore_user_regs
                 ldr     r0, [sp, #S_PSR]                @ Get calling cpsr
                 mov     ip, #I_BIT | MODE_SVC
                 msr     cpsr_c, ip                      @ disable IRQs
                 msr     spsr, r0                        @ save in spsr_svc
                 ldr     lr, [sp, #S_PC]                 @ Get PC
                 ldmia   sp, {r0 - lr}^                  @ Get calling r0 - lr
                 mov     r0, r0
                 add     sp, sp, #S_FRAME_SIZE
                 movs    pc, lr                          @ return & move spsr_svc into cpsr
                 .endm
grassman의 이미지

system call 전후에 사용하는 어셈블리 코드에서는 레지스터가 특별한 용도에 사용되는지 여부를 파악하고 사용하는 것이 필수입니다만... 일단 질문한 내용에 대한 답만 말한다면 "가능하다" 입니다. (불가능하다면 kernel 전체를 어셈블리어로 만들어야 하는 상황이 나옵니다)

C언어 쪽에서 변수를 선언하고 그걸 어셈블리어 쪽에서 사용하는 방법도 있습니다만 여기서는 반대의 예를 들겠습니다.

어셈블리 쪽에서는 32비트 변수를 다음과 같이 선언합니다.

        @ 전역 변수 선언
        .globl __old_pc
__old_pc:
        .long 0

그리고 사용할 때는 이렇게 쓰면 되겠죠.
(주의: r0 레지스터를 사용해도 되는지 여부는 검증해 보지 않았습니다. 그리고 이것은 예제에 불과하므로 정상적인 동작을 보장하지 않습니다.)

        @ fast_restore_user_regs
        ldr     r1, [sp, #S_OFF + S_PSR]        @ get calling cpsr
        ldr     lr, [sp, #S_OFF + S_PC]!        @ get pc
        msr     spsr_cxsf, r1                   @ save in spsr_svc
        ldmdb   sp, {r1 - lr}^                  @ get calling r1 - lr
        mov     r0, r0
        add     sp, sp, #S_FRAME_SIZE - S_PC
 
        @ pc 값 보존
        adr     r0, __old_pc
        str     lr, [r0]
        @ 끝
 
        movs    pc, lr                          @ return & move spsr_svc into cpsr

C언어 쪽에서는 이 변수를 이렇게 사용하면 됩니다.

        extern long __old_pc;
 
        printk("last pc = 0x%08lx\n", __old_pc);

그럼... 적당히 요리해 보기 바랍니다.

zzang9sds의 이미지

.globl 선언의 중복으로 fast_restore_user_regs 매크로가 있는 entry-header.S 에서는 선언을 하지 못하고

entry-common.S에 전역으로 선언을 하고, entry-header.S에서 .extern으로 님께서 알려준 바와같이 pc값을 저장했습니다.

그리고 다른 파일에서 extern으로 선언을 하고 변수에 저장을 해보니 전부 0으로 되어있었습니다.

어셈블리에서 전역으로 선언을하고 다른 어셈블리 파일에서 .extern으로 사용하고, C파일에서 값을 읽어야하는데 이값이 제대로 extern 되지 못하는것 같네요.

Carpe diem~*

Carpe diem~*

익명 사용자의 이미지

adr pseudo code는 명령의 얼마 범위 이내에 참조하는 label이 있어야 합니다.
아무래도 adr의 범위를 벗어나서 label을 잡아버린 듯 합니다. ldr이나 다른 방법으로
변수를 참조하는 것이 좋을 듯 합니다.

zzang9sds의 이미지

ldr lr, =user_pc 또는 ldr lr, user_pc 하고
str pc, [lr] 이렇게 해도 pc값이 제대로 안들어 가네요.

그래서 꼼수로 pc값 저장할 전역 심볼 변수 user_pc의 주소를 알아내서 lr에 다가 넣었습니다. 아래와 같이..
and lr, r0, #MY_ZERO @(MY_ZERO는 0x00000000 입니다.)
add lr, lr, #0xc0000000
add lr, lr, #0x00230000
...
...
str pc, [lr]
이렇게 lr에다가 pc값 저장할 심볼 변수의 주소값을 강제로 넣고, pc값을 그 주소값에 해당하는 곳에 넣어봤으나,
확인해본 결과 그냥 0이네요.

Carpe diem~*

Carpe diem~*

익명 사용자의 이미지

ARM 개발보드를 가진 것이라고는 aesop 3차 보드 밖에 없어서 aesop 기본 커널(Linux 2.6.13)에 테스트를 해 보았습니다.

arch/arm/kernel/entry-common.S

...
 
        .globl __old_pc
__old_pc:
        .long 0
 
        .align  5
/*
 * This is the fast syscall return path.  We do as little as
 * possible here, and this includes saving r0 back into the SVC
 * stack.
 */
ret_fast_syscall:
        disable_irq                             @ disable interrupts
        ldr     r1, [tsk, #TI_FLAGS]
        tst     r1, #_TIF_WORK_MASK
        bne     fast_work_pending
 
        @ fast_restore_user_regs
        ldr     r1, [sp, #S_OFF + S_PSR]        @ get calling cpsr
        ldr     lr, [sp, #S_OFF + S_PC]!        @ get pc
        adr     r2, __old_pc
        str     lr, [r2]
        msr     spsr_cxsf, r1                   @ save in spsr_svc
        ldmdb   sp, {r1 - lr}^                  @ get calling r1 - lr
        mov     r0, r0
        add     sp, sp, #S_FRAME_SIZE - S_PC
        movs    pc, lr                          @ return & move spsr_svc into cpsr
 
...
 
ENTRY(ret_to_user)
ret_slow_syscall:
        disable_irq                             @ disable interrupts
        ldr     r1, [tsk, #TI_FLAGS]
        tst     r1, #_TIF_WORK_MASK
        bne     work_pending
no_work_pending:
        @ slow_restore_user_regs
        ldr     r1, [sp, #S_PSR]                @ get calling cpsr
        ldr     lr, [sp, #S_PC]!                @ get pc
        adr     r2, __old_pc
        str     lr, [r2]
        msr     spsr_cxsf, r1                   @ save in spsr_svc
        ldmdb   sp, {r0 - lr}^                  @ get calling r1 - lr
        mov     r0, r0
        add     sp, sp, #S_FRAME_SIZE - S_PC
        movs    pc, lr                          @ return & move spsr_svc into cpsr

pc값이 저장되는지 확인하기 위해 sys_open system call에서 이전에 호출되었던 pc 값을 출력하도록 해 보았습니다. (다른 system call이나 kernel thread를 사용해도 되지만 테스트를 쉽게 하기 위해 가장 확실하게 호출되는 system call을 찾다 보니 open을 선택한 것임)

fs/open.c

asmlinkage long sys_open(const char __user * filename, int flags, int mode)
{
        char * tmp;
        int fd;
 
        {
                extern long __old_pc;
 
                printk("last pc = 0x%08lx\n", __old_pc);
        }
 
        if (force_o_largefile())
                flags |= O_LARGEFILE;
 
...

결과는 다음과 같습니다.

 
 /) /) 
(='.'=) 
 
login[319]: root login  on `tts/0'
 
last pc = 0x4000bb68
last pc = 0x40005ad8
last pc = 0x40006414
last pc = 0x4000fbc4
last pc = 0x4000fbc4
last pc = 0x4018d970
last pc = 0x40194b14
last pc = 0x4000bb68
last pc = 0x40005ad8
last pc = 0x40006414
last pc = 0x4000fbc4
last pc = 0x4000fbc4
last pc = 0x4018d8f0
last pc = 0x400f42a4
last pc = 0x40134070
last pc = 0x400f3f8c
last pc = 0x400ed6a4
last pc = 0x400ed6a4
last pc = 0x400ed6a4
last pc = 0x400ed6a4
last pc = 0x400ed6a4
last pc = 0x4018da60
last pc = 0x401aaea8
last pc = 0x401c9fa0
last pc = 0x4000fbc4
last pc = 0x401f7ae4
root@godori:~# 

문제의 원인은 다른 곳에 있을 듯 하니 다시 확인해 보시기 바랍니다.

zzang9sds의 이미지

문제는 해당 코드를 어셈블리의 어느 라인에 두느냐 였습니다.
처음에 add sp, sp, #S_FRAME_SIZE - S_PC 이 라인 밑에서 레지스터를 사용코자 하니 리눅스 부팅때 뻗더군요.
그래서 저도 고도리님께서 한것과 같은 곳에서 해결봤습니다.
감사합니다^^

Carpe diem~*

Carpe diem~*

zzang9sds의 이미지

많은 도움이 되었습니다. 감사합니다.
어셈블리 공부좀 해야겠네요^^;;

Carpe diem~*

Carpe diem~*

Hyun의 이미지

사용자 레벨에서의 시스템 콜의 파라미터에 pc를 넣으려는건가요?
C 컴파일러가 함수에서 사용하는 파라미터를 저장하는 메모리나 레지스터의 위치를 알아보시면 좋을 것 같네요.. 아키텍쳐마다 다르긴 한데, 아마 레지스터에 순서대로 저장하지 않나 생각됩니다...

댓글 달기

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