Embedded2009. 12. 26. 09:04
굳은 머리 돌리기 위한 간단한 어셈블러 해석입니다.
오래간만에 어셈블러 한번 볼려고 하니 힘드네요
MIPS에서 어셈블러와 C의 연결을 볼려고 간단한 테스트를 해보는 것을 정리하였습니다.

1. 간단한 함수


int foo( int i , int j )
{
  return i * j;
}

위 코드를 컴파일 해서 어셈블러를 확인합니다.

mips-elf-gcc -S -march=mips32 -O2 test.c -o test.S

그러면

                            LIBCFLAGS="-g -O2 ${flags}" \
        .file   1 "test.c"
        .section .mdebug.abi32
        .previous
        .gnu_attribute 4, 1
        .text
        .align  2
        .globl  foo
        .set    nomips16
        .ent    foo
        .type   foo, @function
foo:
        .frame  $sp,0,$31               # vars= 0, regs= 0/0, args= 0, gp= 0
        .mask   0x00000000,0
        .fmask  0x00000000,0
        .set    noreorder
        .set    nomacro

        j       $31
        mul     $2,$5,$4

        .set    macro
        .set    reorder
        .end    foo
        .size   foo, .-foo
        .ident  "GCC: (GNU) 4.4.2"

과 같은 코드를 얻을 수 있습니다.

코드를 보면 jump 다음에 mul을 하는 것을 알 수 있습니다. 즉 delay slot을 기본적으로 architecture에서 가지고 가므로, jump 명령이 먼저와도 분기를 마칠때에는 레지스터에 값이 기록되게 되어 있습니다.

리턴되는 값은 2번 레지스터에 기록되고
인자는 4번과 5번으로 기록됩니다.

2. unsigned 64비트 곱셈 test


unsigned long long  foo( unsigned long long i , unsigned long long  j)
{
  return i* j ;
}

../local/bin/mips-elf-gcc -S test3.c -o test3.S -O2 -march=mips32
으로 컴파일해서 결과를 보면 아래와 같습니다.

        .file   1 "test3.c"
        .section .mdebug.abi32
        .previous
        .gnu_attribute 4, 1
        .text
        .align  2
        .globl  foo
        .set    nomips16
        .ent    foo
        .type   foo, @function
foo:
        .frame  $sp,0,$31               # vars= 0, regs= 0/0, args= 0, gp= 0
        .mask   0x00000000,0
        .fmask  0x00000000,0
        .set    noreorder
        .set    nomacro

        mul     $2,$4,$7
        multu   $7,$5
        mflo    $9
        mfhi    $8
        mul     $3,$6,$5
        addu    $2,$3,$2
        addu    $2,$2,$8
        j       $31
        move    $3,$9

        .set    macro
        .set    reorder
        .end    foo
        .size   foo, .-foo
        .ident  "GCC: (GNU) 4.4.2"

입력이 64비트 두개의 값이므로,
4개의 레지스터가 입력으로 들어와야 합니다.


$4,
$7
$5
$6이 입력이 됩니다.

64비트 입력은 두개의 레지스터이고 두 64비트의 곱셈은

              A B
x            C D
----------------
         [B x D]
    [A x D]
    [B x C]
[A x C]
-------------
Result

입니다.

그런데 결과값이 64비트만 필요하므로 [A x C]는 불필요 합니다. 따라서 곱셈이 3번만 하면됩니다.
위의 코드에서 곱셈이 3번 나오는 이유입니다.

$7과 $5를 곱하면 그 결과가 Hi,Lo레지스터에 기록됩니다.
이를 $8,$9에 옮겨 두게 됩니다. [B x D]가 $8 $9입니다.

$4 $7을 곱한것은 그 결과로 하위 32비트가 필요하므로 [A x D] 가 됩니다. 따라서 공통으로 쓰이는 $7이 D임을 알수 있고, [ A : B ]는 [$4,$5]임을 알수 있습니다.
나머지 입력인 $6이 [ $6 : $7 ] 입니다.

$6 x $5를 한 하위 32비트를 사용하게 되므로 이 값이 $3에 들어갑니다.

최종적으로는 결과값의 상위 32비트에 해당되는 값은 각각의 덧셈의 결과이므로
$2 + $3 + $8이 그 결과값인 상위 32비트입니다.

이 결과값이 $2에 그리고 [BxD]의 결과값이 $3으로 옮기게 되므로 최종 결과치는
[$2:$3]이 됩니다.




'Embedded' 카테고리의 다른 글

[MIPS] Assembler 코드 살펴보기 - 3  (0) 2009.12.30
[MIPS] Assembler 코드 살펴보기 - 2  (0) 2009.12.29
Fedora 메일서버 세팅  (2) 2009.12.21
[MIPS] Simulator  (0) 2009.12.20
MPEG 1/2 Reference Site  (0) 2009.12.13
Posted by GUNDAM_IM