GCC가 int 나누기에 대해 올바른 어셈블리 코드를 생성하지 않는 이유는 무엇입니까?

카림 마나 우일

다음 C 코드를 작성했습니다. 그러나 런타임에서 변수에 대한 잘못된 값을 제공 sb했기 때문에 GDB로 디버깅하려고 시도했으며 int 나누기 E(vdes->addr, bs)( #define E(X,Y) X/Y) 의 어셈블리 코드 가 완전히 이해하기 어렵고 옳은 일을하지 않는 것 같습니다.

파일 : main.c

typedef struct virtual_file_descriptor
{
    int     dfb;
    int     addr;

} vfd;

vfd vdes;

if(!strcmp(argv[1], "write")){
        vdes.dfb = atoi(argv[2]);
        vdes.addr = atoi(argv[3]);
        vwrite(&vdes, inbuffer, atoi(argv[4]));
    }

파일 : vwrite.c

#define E(X,Y)  X/Y
#define bs      sizeof(D_Record)*MAX_BLOCK_ENTRIES

int vwrite(vfd *vdes, char *buffer, int size){
    if(!vdes)
        return -1;

    int sb, nb, offset;

    sb      = E(vdes->addr, bs) + 1;     // i did 140/280 => wrong result
    offset  = vdes->addr - (sb - 1) * bs;

    printf("size=%d bs=%d   addr=%d sb=%d   offset=%d\n\n", size, bs, vdes->addr, sb, offset);

}

int 디비전을 위해 생성 된 어셈블리 언어는 다음과 같습니다 (그것이 잘못되었으며 산술 분할을 수행하는 노래를 포함하지 않음).

(gdb) n
58      sb      = E(vdes->addr, bs) + 1;
(gdb) x/10i $pc
=> 0x80001c3d <vwrite+39>:  mov    0x8(%ebp),%eax
   0x80001c40 <vwrite+42>:  mov    0x4(%eax),%eax
   0x80001c43 <vwrite+45>:  shr    $0x2,%eax
   0x80001c46 <vwrite+48>:  mov    $0x24924925,%edx
   0x80001c4b <vwrite+53>:  mul    %edx
   0x80001c4d <vwrite+55>:  mov    %edx,%eax
   0x80001c4f <vwrite+57>:  shl    $0x2,%eax
   0x80001c52 <vwrite+60>:  add    %edx,%eax
   0x80001c54 <vwrite+62>:  add    %eax,%eax
   0x80001c56 <vwrite+64>:  add    $0x1,%eax
   0x80001c59 <vwrite+67>:  mov    %eax,-0x2c(%ebp)
   0x80001c5c <vwrite+70>:  mov    0x8(%ebp),%eax
   0x80001c5f <vwrite+73>:  mov    0x4(%eax),%eax
   0x80001c62 <vwrite+76>:  mov    %eax,%edx

동일한 코드 시퀀스를 새 독립 실행 형 파일에 복사했는데 모든 것이 잘 작동합니다 (결과 수정 및 어셈블리 코드 수정). 그래서 왜 첫 번째 코드가 작동하지 않는지 궁금해졌습니다.

파일 : test.c

#define E(X,Y) X/Y

int main(int argc, char **argv){

    int sb = E(atoi(argv[1]), atoi(argv[2]));

    return 0;
}

이전 코드에 대해 생성 된 어셈블리 코드 (정확하게 이해하기 쉽고 int 디비전을 수행하기위한 올바른 코드) :

   .
   .
   call atoi
   .
   call atoi
   .
   .
   0x800005db <main+75>:    mov    %eax,%ecx
   0x800005dd <main+77>:    mov    %edi,%eax
   0x800005df <main+79>:    cltd   
   0x800005e0 <main+80>:    idiv   %ecx
   0x800005e2 <main+82>:    mov    %eax,-0x1c(%ebp)
rcgldr

원래 질문은

#define bs      280

나중에 다음으로 변경되었습니다.

#define bs      sizeof(D_Record)*MAX_BLOCK_ENTRIES

다른 표현식에서 bs를 사용하는 문제를 방지하려면 다음과 같이해야합니다.

#define bs      (sizeof(D_Record)*MAX_BLOCK_ENTRIES)

E에 대한 정의는 다음과 같아야합니다.

#define E(X,Y) ((X)/(Y))

생성 된 어셈블리 코드는

#define bs      sizeof(D_Record)*MAX_BLOCK_ENTRIES
#define E(X,Y) X/Y
    ... E(vdes->addr, bs) ...

따라서 shift를 사용하여 28로 나누고 곱한 다음 10을 곱하십시오.

        mov    0x4(%eax),%eax       ;eax = dividend
        shr    $0x2,%eax            ;eax = dividend/4 (pre shift)
        mov    $0x24924925,%edx     ;edx = multiply constant
        mul    %edx                 ;edx = dividend/28 (no post shift)
        mov    %edx,%eax            ;eax = (dividend/28)*10
        shl    $0x2,%eax
        add    %edx,%eax
        add    %eax,%eax

eax = edx * 10 시퀀스의 경우 lea가 사용되지 않은 이유를 잘 모르겠습니다.

        lea    (%edx,%edx,2),eax    ;eax = edx*5
        add    %eax,%eax            ;eax = edx*10

상수로 나누기가 곱셈과 시프트로 변환되는 방법에 대한 설명이있는 이전 스레드에 연결합니다.

GCC는 정수 나눗셈을 구현할 때 왜 곱셈을 이상한 숫자로 사용합니까?

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

서로 다른 디버거가 동일한 함수에 대해 서로 다른 어셈블리 코드를 출력하는 이유는 무엇입니까?

분류에서Dev

이 코드가 올바른 해시를 생성하지 않는 이유는 무엇입니까?

분류에서Dev

이 어셈블리 코드에 짝수 또는 홀수를 추가하는 올바른 방법은 무엇입니까?

분류에서Dev

x86-64 C / C ++ 컴파일러가이 코드에 대해 더 효율적인 어셈블리를 생성하지 않는 이유는 무엇입니까?

분류에서Dev

비교 작업에 대한 올바른 결과를 제공하지 않는 어셈블리 코드

분류에서Dev

이 어셈블리 코드에서 세그 오류가 발생하는 이유는 무엇입니까?

분류에서Dev

GCC에서 내 보낸 vtable 어셈블리 코드에서이 두 가지는 무엇입니까?

분류에서Dev

한 코드가 firebase에서 올바른 키를 제공하고 다른 코드는 제공하지 않는 이유는 무엇입니까?

분류에서Dev

autowired와 리소스가 맵에 대해 다른 키를 생성하는 이유는 무엇입니까?

분류에서Dev

이 코드에 대해 유효하지 않다는 오류가 발생하는 이유는 무엇입니까?

분류에서Dev

이 PIC 어셈블러 코드에서 비트가 이동하지 않는 이유는 무엇입니까?

분류에서Dev

버전 6 Unix에서이 TMG의 어셈블리 코드를 이해하는 방법은 무엇입니까?

분류에서Dev

이 코드가 올바른 결과를 반환하지 않는 이유는 무엇입니까?

분류에서Dev

내 코드가 올바른 최소 차이를 인쇄하지 않는 이유는 무엇입니까?

분류에서Dev

gcc가 다른 형태의 정수 리터럴을 사용하는 프로그램에 대해 다른 컴파일 된 바이너리를 생성하는 이유는 무엇입니까?

분류에서Dev

InternalVisibleTo를 사용하지 않고 다른 어셈블리에서 한 어셈블리의 내부 속성에 액세스하는 방법은 무엇입니까?

분류에서Dev

Linux의 C 소스 코드에서 nasm 컴파일 가능한 어셈블리 코드를 생성하는 방법은 무엇입니까?

분류에서Dev

SQL Server가 코드를 올바르게 처리하지 않는 이유는 무엇입니까?

분류에서Dev

생성자 / 소멸자가 g ++ 생성 어셈블리 코드에서 이와 같이 정의되는 이유는 무엇입니까?

분류에서Dev

핵심 데이터-내 NSPredicate가 올바른 SQL 쿼리를 생성하지 않는 이유는 무엇입니까?

분류에서Dev

gdb가 디스 어셈블리에 해당하는 두 소스 코드를 함께 인쇄하도록하는 방법은 무엇입니까?

분류에서Dev

VS2013이 위성 어셈블리를 생성하지 않는 이유는 무엇입니까?

분류에서Dev

인터럽트가 C 코드로 생성되지 않고 어셈블리 명령으로 쉽게 생성되는 이유는 무엇입니까?

분류에서Dev

프로젝트 어셈블리-프로젝트 어셈블리 "학습 모음 문자"코드에 마크를 추가하는 방법은 무엇입니까?

분류에서Dev

올바른 방법으로 읽기가 일관된 결과를 생성하지 않는 이유는 무엇입니까?

분류에서Dev

.lua 또는 바이트 코드에서 어셈블리 코드를 얻는 방법은 무엇입니까?

분류에서Dev

int [] 배열에 대한 해시 키를 생성하는 가장 빠른 방법은 무엇입니까?

분류에서Dev

이 어셈블리 코드가 무한 루프에있는 이유는 무엇입니까?

분류에서Dev

어셈블리 코드에서 이러한 오류가 발생하는 이유는 무엇입니까 (옵션 케이스 맵 : 없음)?

Related 관련 기사

  1. 1

    서로 다른 디버거가 동일한 함수에 대해 서로 다른 어셈블리 코드를 출력하는 이유는 무엇입니까?

  2. 2

    이 코드가 올바른 해시를 생성하지 않는 이유는 무엇입니까?

  3. 3

    이 어셈블리 코드에 짝수 또는 홀수를 추가하는 올바른 방법은 무엇입니까?

  4. 4

    x86-64 C / C ++ 컴파일러가이 코드에 대해 더 효율적인 어셈블리를 생성하지 않는 이유는 무엇입니까?

  5. 5

    비교 작업에 대한 올바른 결과를 제공하지 않는 어셈블리 코드

  6. 6

    이 어셈블리 코드에서 세그 오류가 발생하는 이유는 무엇입니까?

  7. 7

    GCC에서 내 보낸 vtable 어셈블리 코드에서이 두 가지는 무엇입니까?

  8. 8

    한 코드가 firebase에서 올바른 키를 제공하고 다른 코드는 제공하지 않는 이유는 무엇입니까?

  9. 9

    autowired와 리소스가 맵에 대해 다른 키를 생성하는 이유는 무엇입니까?

  10. 10

    이 코드에 대해 유효하지 않다는 오류가 발생하는 이유는 무엇입니까?

  11. 11

    이 PIC 어셈블러 코드에서 비트가 이동하지 않는 이유는 무엇입니까?

  12. 12

    버전 6 Unix에서이 TMG의 어셈블리 코드를 이해하는 방법은 무엇입니까?

  13. 13

    이 코드가 올바른 결과를 반환하지 않는 이유는 무엇입니까?

  14. 14

    내 코드가 올바른 최소 차이를 인쇄하지 않는 이유는 무엇입니까?

  15. 15

    gcc가 다른 형태의 정수 리터럴을 사용하는 프로그램에 대해 다른 컴파일 된 바이너리를 생성하는 이유는 무엇입니까?

  16. 16

    InternalVisibleTo를 사용하지 않고 다른 어셈블리에서 한 어셈블리의 내부 속성에 액세스하는 방법은 무엇입니까?

  17. 17

    Linux의 C 소스 코드에서 nasm 컴파일 가능한 어셈블리 코드를 생성하는 방법은 무엇입니까?

  18. 18

    SQL Server가 코드를 올바르게 처리하지 않는 이유는 무엇입니까?

  19. 19

    생성자 / 소멸자가 g ++ 생성 어셈블리 코드에서 이와 같이 정의되는 이유는 무엇입니까?

  20. 20

    핵심 데이터-내 NSPredicate가 올바른 SQL 쿼리를 생성하지 않는 이유는 무엇입니까?

  21. 21

    gdb가 디스 어셈블리에 해당하는 두 소스 코드를 함께 인쇄하도록하는 방법은 무엇입니까?

  22. 22

    VS2013이 위성 어셈블리를 생성하지 않는 이유는 무엇입니까?

  23. 23

    인터럽트가 C 코드로 생성되지 않고 어셈블리 명령으로 쉽게 생성되는 이유는 무엇입니까?

  24. 24

    프로젝트 어셈블리-프로젝트 어셈블리 "학습 모음 문자"코드에 마크를 추가하는 방법은 무엇입니까?

  25. 25

    올바른 방법으로 읽기가 일관된 결과를 생성하지 않는 이유는 무엇입니까?

  26. 26

    .lua 또는 바이트 코드에서 어셈블리 코드를 얻는 방법은 무엇입니까?

  27. 27

    int [] 배열에 대한 해시 키를 생성하는 가장 빠른 방법은 무엇입니까?

  28. 28

    이 어셈블리 코드가 무한 루프에있는 이유는 무엇입니까?

  29. 29

    어셈블리 코드에서 이러한 오류가 발생하는 이유는 무엇입니까 (옵션 케이스 맵 : 없음)?

뜨겁다태그

보관