1

I was looking through the generated assembly from my compiler and noticed a series of jump commands that just go to the next memory address listed. I was wondering what the heck the purpose of that is. This was generated from gcc compiler. I used otool to disassemble. The snippet of assembly is toward the bottom of the list right before the functions are listed, so I'm sure it has to do with the main function and since it's just calls to printf and if else statements I can't make heads or tails of what it does... here is a link to full source: https://drive.google.com/open?id=1INI3i4ZP7dtJVQ5n4twA6RCG_sdbjVxd

It has make file included, the program with take an argument such as m2k for miles to kilometers then the value you want so to convert 3 miles to kilometers the syntax would be : convert m2k 3.

0000000100000c95    cvtsd2ss    %xmm0, %xmm0
0000000100000c99    callq   0x100000ee0
0000000100000c9e    leaq    0x2a5(%rip), %rdi
0000000100000ca5    cvtss2sd    %xmm0, %xmm0
0000000100000ca9    movb    $0x1, %al
0000000100000cab    callq   0x100000f0a
0000000100000cb0    movl    %eax, -0x38(%rbp)
0000000100000cb3    jmp 0x100000cb8
0000000100000cb8    jmp 0x100000cbd
0000000100000cbd    jmp 0x100000cc2
0000000100000cc2    jmp 0x100000cc7
0000000100000cc7    jmp 0x100000ccc
0000000100000ccc    jmp 0x100000cd1
0000000100000cd1    jmp 0x100000cd6
0000000100000cd6    jmp 0x100000cdb
0000000100000cdb    jmp 0x100000ce0
0000000100000ce0    xorl    %eax, %eax
0000000100000ce2    addq    $0x40, %rsp
0000000100000ce6    popq    %rbp
0000000100000ce7    retq
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
jergp
  • 21
  • 5
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/192294/discussion-on-question-by-jergp-generated-assembly-code-contains-a-series-of-jum). – Samuel Liew Apr 24 '19 at 06:04
  • Were you actually using clang, on a Mac where `gcc` is actually clang? That's just confusing for everyone, because I'm pretty sure GCC's back-end never emits code like this (even at `-O0`). I added a `clang` tag based on Gene's answer. – Peter Cordes Apr 25 '19 at 14:45
  • it is actually. It looks like gcc is aliased to clang. – jergp Apr 26 '19 at 02:07

2 Answers2

5

LLVM/clang-1001.0.46.4 does this on my MacBook.

This appears to be an artifact of compiling chained else ifs without optimization. For the code

if (E == 0) A; 
else if (F == 0) B;
else C;

the compiler is generating

  <evaluate E into eax>
  cmp eax, 0
  jne EvalF
  <code for A>
  jmp EndIfE

EvalF:
  <evaluate F into eax>
  cmp eax, 0
  jne DoC
  <code for B>
  jmp EndIfF

DoC:
  <code for C>

EndIfF: goto EndIfE
EndIfE: 
  <rest of program>

So here there's one useless jump. With more chained ifs you get more of the same useless jumps.

It's almost certain that this happens because the code generator creates an empty basic block data structure to represent the code that runs after each if else. For a single if else that basic block is eventually filled with the code that runs after the statement is complete. But when if elses are chained, only the outermost block contains executable code. The rest remain empty.

It's natural for an empty basic block to be compiled to a jmp instruction because every basic block ends in a branch to another basic block. (Indeed that's part of the definition.) Here the jmp goes to a basic block that happens to finally be compiled to the address immediately following, but early code generation is normally not concerned with inefficiency at this level. Rather it's all about correctness, and the useless jump is not an error.

You can learn more about basic blocks and control flow graphs in the Wikipedia page.

The compiler is running with -O0. No optimization. Code generation quirks like this are to be expected. If you compile with -O1 or higher, they'll disappear. Jump threading is a standard optimization algorithm.

Gene
  • 46,253
  • 4
  • 58
  • 96
-1

Its the list of if's as far as i know.

if (strcmp(argv[1], "c2f") == 0 ) {
    printf("%.1f F\n", celciusToFarenheit( atof(argv[2])));
}
else if (strcmp(argv[1], "f2c") == 0){
    printf("%.1f C\n", farenheitToCelcius( atof(argv[2])));
}
else if (strcmp(argv[1], "c2k") == 0){
    printf("%.1f K\n", celciusToKelvin( atof(argv[2])));
}
else if (strcmp(argv[1], "f2k") == 0){
    printf("%.1f K\n", farenheitToKelvin( atof(argv[2])));
}
else if (strcmp(argv[1], "k2f") == 0){
    printf("%.1f F\n", kelvinToFarenheit( atof(argv[2])));
}
else if (strcmp(argv[1], "k2c") ==0){
    printf("%.1f C\n", kelvinToCelcius( atof(argv[2])));
}
else if (strcmp(argv[1], "k2m") == 0){
    printf("%.1f M\n", kilometersToMiles( atof(argv[2])));
}
else if (strcmp(argv[1], "m2k") == 0){
    printf("%.1f K\n", milesToKilometers( atof(argv[2])));
}
else if (strcmp(argv[1], "f2m") == 0){
    printf("%.1f M\n", feetToMeters( atof(argv[2])));
}
else if ( strcmp(argv[1], "m2f")  == 0){
    printf("%.1f F\n", metersToFeet( atof(argv[2])));
}

8 If statement, 8 JMP's + 1 Print, 1 JMP

Comet
  • 260
  • 2
  • 8
  • 1
    I didn't think so since each jump goes to the next address which has a jump the the next jump address. When optimized with the O3 flag it does not produce the series of jumps. – jergp Apr 24 '19 at 04:01
  • Correct me if i am wrong but it make sense as the 03 Flag enable inline-functions flag. So there is no jump to be made? – Comet Apr 24 '19 at 04:24
  • It does, however looking at the generated assembly, it jumps from one instruction address to the next unconditionally and I've never seen that before. all the if statements generate a compare. In basic it would look like : 10 goto 20; 20 goto 30 ect... – jergp Apr 24 '19 at 04:32
  • https://stackoverflow.com/a/9971443/7184594 this guy show how to view both source and assembly at the same time – Comet Apr 24 '19 at 04:41
  • I'm sorry my friend, I don't understand your point. – jergp Apr 24 '19 at 04:45
  • Well if you run the app and step through it youd be able to see what triggers the JMP because the source will be in front of you at the same time. Im not at a computer right now so i cant do it sorry. – Comet Apr 24 '19 at 04:49
  • 1
    `jmp` is an *unconditional* jump. You're thinking of `jcc`, like `jne`. But even then, there's no reason why a compiler would emit a sequence of multiple jump-next-instruction with no flag-setting insns between them. Or even *one* jump-next-instruction, whether it's conditional or not, because that's just an expensive NOP that always goes to the next instruction. See https://godbolt.org/z/0XvPJb for `gcc -O0` and `gcc -O3` code-gen for a main with 4 of your `if` clauses compiled; see what the asm *actually* looks like. (@jergp: this answer makes no sense, but neither does your asm.) – Peter Cordes Apr 24 '19 at 06:07