[완료]어셈블리에서 C변수 사용이 가능한가요?
글쓴이: zzang9sds / 작성시간: 금, 2007/09/28 - 7:43오후
아래 소스는 /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
Forums:
system call이라는 점이 좀 걸리지만 가능하기는 합니다.
system call 전후에 사용하는 어셈블리 코드에서는 레지스터가 특별한 용도에 사용되는지 여부를 파악하고 사용하는 것이 필수입니다만... 일단 질문한 내용에 대한 답만 말한다면 "가능하다" 입니다. (불가능하다면 kernel 전체를 어셈블리어로 만들어야 하는 상황이 나옵니다)
C언어 쪽에서 변수를 선언하고 그걸 어셈블리어 쪽에서 사용하는 방법도 있습니다만 여기서는 반대의 예를 들겠습니다.
어셈블리 쪽에서는 32비트 변수를 다음과 같이 선언합니다.
그리고 사용할 때는 이렇게 쓰면 되겠죠.
(주의: r0 레지스터를 사용해도 되는지 여부는 검증해 보지 않았습니다. 그리고 이것은 예제에 불과하므로 정상적인 동작을 보장하지 않습니다.)
C언어 쪽에서는 이 변수를 이렇게 사용하면 됩니다.
그럼... 적당히 요리해 보기 바랍니다.
문제가 있네요..
.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는 사용할 때 주의해야 합니다.
adr pseudo code는 명령의 얼마 범위 이내에 참조하는 label이 있어야 합니다.
아무래도 adr의 범위를 벗어나서 label을 잡아버린 듯 합니다. ldr이나 다른 방법으로
변수를 참조하는 것이 좋을 듯 합니다.
ldr로 해도...
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
pc값이 저장되는지 확인하기 위해 sys_open system call에서 이전에 호출되었던 pc 값을 출력하도록 해 보았습니다. (다른 system call이나 kernel thread를 사용해도 되지만 테스트를 쉽게 하기 위해 가장 확실하게 호출되는 system call을 찾다 보니 open을 선택한 것임)
fs/open.c
결과는 다음과 같습니다.
문제의 원인은 다른 곳에 있을 듯 하니 다시 확인해 보시기 바랍니다.
문제는 해당 코드를 어셈블리의 어느 라인에...
문제는 해당 코드를 어셈블리의 어느 라인에 두느냐 였습니다.
처음에 add sp, sp, #S_FRAME_SIZE - S_PC 이 라인 밑에서 레지스터를 사용코자 하니 리눅스 부팅때 뻗더군요.
그래서 저도 고도리님께서 한것과 같은 곳에서 해결봤습니다.
감사합니다^^
Carpe diem~*
Carpe diem~*
감사합니다^^
많은 도움이 되었습니다. 감사합니다.
어셈블리 공부좀 해야겠네요^^;;
Carpe diem~*
Carpe diem~*
사용자 레벨에서의
사용자 레벨에서의 시스템 콜의 파라미터에 pc를 넣으려는건가요?
C 컴파일러가 함수에서 사용하는 파라미터를 저장하는 메모리나 레지스터의 위치를 알아보시면 좋을 것 같네요.. 아키텍쳐마다 다르긴 한데, 아마 레지스터에 순서대로 저장하지 않나 생각됩니다...
댓글 달기