5

In the following instructions, how does the addq work? It only has one operand, the book claims that it increments %rdx, but %rdx is not in this instruction. I am so confused...

This is from the book Computer Systems A Programmers Perspective, 3rd Edition.

enter image description here

enter image description here

enter image description here

Student222
  • 3,021
  • 2
  • 19
  • 24
  • 4
    That's a mistake in the book. Also the next line is writing back `%eax` (which is `i`) not `%edx`. Those two instructions should be `addq $1, %rdx; movq %rdx, cnt(%rip)`. Or the whole block can be replaced by `addq $1, cnt(%rip)`. – Jester Jan 17 '18 at 15:28
  • @Jester Thank you very much! your instructions makes much more sense! I like this CSAPP book very much, but mistakes like this are so annoying! – Student222 Jan 17 '18 at 15:32
  • Please include the title of the book so that others with the same question will find it. – Raymond Chen Jan 17 '18 at 15:39
  • @RaymondChen Good suggestion, I have added the book name in the title and body. : ) – Student222 Jan 17 '18 at 15:54
  • 1
    BTW, it seems the practice problem in the global edition of this textbook were replaced by the publisher with buggy crap. http://csapp.cs.cmu.edu/3e/errata.html. e.g. [CS:APP example uses idivq with two operands?](//stackoverflow.com/q/57998998) – Peter Cordes Feb 27 '20 at 16:42

1 Answers1

3

As @Jester pointed out in the comment. It is indeed an error. I actually typed in the program and compiled it using gcc on linux. Below is the results.

C program: badcnt.c

/*
 * badcnt.c - An improperly synchronized counter program
 */
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>

void *thread(void *vargp);  /* Thread routine prototype */

/* Global shared variable */
volatile int cnt = 0; /* Counter */

int main(int argc, char **argv)
{
  int niters;
  pthread_t tid1, tid2;

  /* Check input argument */
  if (argc != 2) {
    printf("usage: %s <niters>\n", argv[0]);
    exit(0);
  }
  niters = atoi(argv[1]);

  /* Create threads and wait for them to finish */
  pthread_create(&tid1, NULL, thread, &niters);
  pthread_create(&tid2, NULL, thread, &niters);
  pthread_join(tid1, NULL);
  pthread_join(tid2, NULL);

  /* Check result */
  if (cnt != (2 * niters))
    printf("BOOM! cnt=%d\n", cnt);
  else
    printf("OK cnt=%d\n", cnt);
  exit(0);
}

/* Thread routine */
void *thread(void *vargp)
{
  int i, niters = *((int *)vargp);

  for (i = 0; i < niters; i++)
    cnt++;

  return NULL;
}

Compile using gcc 6.3.0

$ gcc -pthread -Og -S badcnt.c

Below is the contents in badcnt.s

        .file   "badcnt.c"
        .text
        .globl  thread
        .type   thread, @function
thread:
.LFB20:
        .cfi_startproc
        movl    (%rdi), %ecx
        movl    $0, %edx
        jmp     .L2
.L3:
        movl    cnt(%rip), %eax
        addl    $1, %eax
        movl    %eax, cnt(%rip)
        addl    $1, %edx
.L2:
        cmpl    %ecx, %edx
        jl      .L3
        movl    $0, %eax
        ret
        .cfi_endproc
.LFE20:
        .size   thread, .-thread
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "usage: %s <niters>\n"
.LC1:
        .string "BOOM! cnt=%d\n"
.LC2:
        .string "OK cnt=%d\n"
        .text
        .globl  main
        .type   main, @function
main:
.LFB19:
        .cfi_startproc
        subq    $40, %rsp
        .cfi_def_cfa_offset 48
        cmpl    $2, %edi
        je      .L5
        movq    (%rsi), %rsi
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf
        movl    $0, %edi
        call    exit
.L5:
        movq    8(%rsi), %rdi
        movl    $10, %edx
        movl    $0, %esi
        call    strtol
        movl    %eax, 28(%rsp)
        leaq    28(%rsp), %rcx
        movl    $thread, %edx
        movl    $0, %esi
        leaq    16(%rsp), %rdi
        call    pthread_create
        leaq    28(%rsp), %rcx
        movl    $thread, %edx
        movl    $0, %esi
        leaq    8(%rsp), %rdi
        call    pthread_create
        movl    $0, %esi
        movq    16(%rsp), %rdi
        call    pthread_join
        movl    $0, %esi
        movq    8(%rsp), %rdi
        call    pthread_join
        movl    28(%rsp), %eax
        addl    %eax, %eax
        movl    cnt(%rip), %edx
        cmpl    %edx, %eax
        je      .L6
        movl    cnt(%rip), %esi
        movl    $.LC1, %edi
        movl    $0, %eax
        call    printf
.L7:
        movl    $0, %edi
        call    exit
.L6:
        movl    cnt(%rip), %esi
        movl    $.LC2, %edi
        movl    $0, %eax
        call    printf
        jmp     .L7
        .cfi_endproc
.LFE19:
        .size   main, .-main
        .globl  cnt
        .bss
        .align 4
        .type   cnt, @object
        .size   cnt, 4
cnt:
        .zero   4
        .ident  "GCC: (GNU) 6.3.0"
        .section        .note.GNU-stack,"",@progbits

So it confirms the mistake of the book.

Student222
  • 3,021
  • 2
  • 19
  • 24
  • That's odd that `-Og` doesn't use `addl $1, cnt(%rip)`. That executes slightly more efficiently than separate load/add/store, on modern Intel CPUs. (And interestingly, [more efficiently than `incl $1, cnt(%rip)` because an `add` uop can micro-fuse a load](https://stackoverflow.com/questions/36510095/inc-instruction-vs-add-1-does-it-matter).) Perhaps the authors meant to write `inc %edx` instead of `add`? Or else it's just a copy/paste editing error, because I think that was supposed to be real compiler output.) – Peter Cordes Jan 17 '18 at 20:02
  • Oh nvm, it's not odd, it's just what gcc always does with `volatile`. We get the same thing from `gcc -O3` on the Godbolt compiler explorer: https://godbolt.org/g/9AuFHq. (And yes, you needed `volatile` to use to stop it from compiling the loop to `addl %reg, cnt(%rip)` with no loop, unless you disabled optimizations.) Clang doesn't have that missed-optimization for `volatile`, but it uses `incl` in an unrolled loop instead of `addl`. – Peter Cordes Jan 17 '18 at 20:07
  • @PeterCordes Thank you very much for the information! The codbolt.org compiler explorer looks very cool~ bookmarked! : ) – Student222 Jan 17 '18 at 20:31