Skip to content

Instantly share code, notes, and snippets.

@matthw
Last active July 31, 2023 11:26
Show Gist options
  • Save matthw/7e360de6614191ab95676e8ba1c32072 to your computer and use it in GitHub Desktop.
Save matthw/7e360de6614191ab95676e8ba1c32072 to your computer and use it in GitHub Desktop.

Useless code:

#include <stdio.h>


void nop(void)
{
    asm("nop");
}

int main(void)
{
    asm("push %r10");
    asm("movq $8, %r10");
    asm("pop %r10");

    for (int i=0; i<10000; i++)
    {
        nop();
    }

    return 0xdead;
}

compiled with the junk to:

0000000000001129 <nop>:
    1129:	55                   	push   rbp
    112a:	48 89 e5             	mov    rbp,rsp
    112d:	90                   	nop
    112e:	90                   	nop
    112f:	5d                   	pop    rbp
    1130:	c3                   	ret

0000000000001131 <main>:
    1131:	55                   	push   rbp
    1132:	48 89 e5             	mov    rbp,rsp
    1135:	48 83 ec 10          	sub    rsp,0x10
    1139:	41 52                	push   r10
    113b:	49 c7 c2 08 00 00 00 	mov    r10,0x8
    1142:	41 5a                	pop    r10
    1144:	c7 45 fc 00 00 00 00 	mov    DWORD PTR [rbp-0x4],0x0
    114b:	eb 09                	jmp    1156 <main+0x25>
    114d:	e8 d7 ff ff ff       	call   1129 <nop>
    1152:	83 45 fc 01          	add    DWORD PTR [rbp-0x4],0x1
    1156:	81 7d fc 0f 27 00 00 	cmp    DWORD PTR [rbp-0x4],0x270f
    115d:	7e ee                	jle    114d <main+0x1c>
    115f:	b8 ad de 00 00       	mov    eax,0xdead
    1164:	c9                   	leave
    1165:	c3                   	ret

1. emit llvm ir with retdec

% retdec-decompiler --select-decode-only --select-functions=nop,main ~/tmp/retdec-test/test

shit loop is still here:

define i64 @nop() local_unnamed_addr {
dec_label_pc_1129:
  %0 = alloca i64, align 8
  %1 = load i64, i64* %0, align 8
  ret i64 %1, !insn.addr !0
}

define i64 @main(i64 %argc, i8** %argv) local_unnamed_addr {
dec_label_pc_1131:
  %storemerge1.reg2mem = alloca i32, align 4, !insn.addr !1
  store i32 0, i32* %storemerge1.reg2mem, align 4
  br label %dec_label_pc_114d

dec_label_pc_114d:                                ; preds = %dec_label_pc_114d, %dec_label_pc_1131
  %storemerge1.reload = load i32, i32* %storemerge1.reg2mem, align 4
  %0 = call i64 @nop(), !insn.addr !2
  %1 = add nuw nsw i32 %storemerge1.reload, 1, !insn.addr !3
  %exitcond = icmp eq i32 %1, 10000
  store i32 %1, i32* %storemerge1.reg2mem, align 4, !insn.addr !4
  br i1 %exitcond, label %dec_label_pc_115f, label %dec_label_pc_114d, !insn.addr !4

dec_label_pc_115f:                                ; preds = %dec_label_pc_114d
  ret i64 57005, !insn.addr !5
}

2. optimization pass with clang

% clang -O2 -S -emit-llvm -o - test.ll   > test_opt.ll

looks better now:

; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
define i64 @nop() local_unnamed_addr #0 {
dec_label_pc_1129:
  ret i64 undef, !insn.addr !0
}

; Function Attrs: nofree norecurse nosync nounwind readnone
define i64 @main(i64 %argc, i8** nocapture readnone %argv) local_unnamed_addr #1 {
dec_label_pc_1131:
  ret i64 57005, !insn.addr !1
}

3. recompile

% llvm-as test_opt.ll -o test_opt.bc
% clang -nostdlib test_opt.bc -c -o test_opt.o

"optimized" code with a clean main:

% objdump -M intel -d test_opt.o 

test_opt.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <nop>:
   0:	c3                   	ret
   1:	66 2e 0f 1f 84 00 00 	cs nop WORD PTR [rax+rax*1+0x0]
   8:	00 00 00 
   b:	0f 1f 44 00 00       	nop    DWORD PTR [rax+rax*1+0x0]

0000000000000010 <main>:
  10:	b8 ad de 00 00       	mov    eax,0xdead
  15:	c3                   	ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment