I parsed the bytes you provided and got the following code:
(__TEXT,__text) section f: 00000000 movb 0x08(%esp),%cl 00000004 xorl %eax,%eax 00000006 testb $0xe0,%cl 00000009 jne 0x00000011 0000000b movl 0x04(%esp),%eax 0000000f shll %cl,%eax 00000011 retl $0x0008
Which is definitely more complicated than the source code provided by the author. It checks that the second operand is not too large, for example, which is not in the code that you showed at all (see Section "Editing 2" below for a more complete analysis). Here's a simple stdcall function that combines two arguments and returns the result:
mov 4(%esp), %eax add 8(%esp), %eax ret $8
An assembly that gives me this conclusion:
(__TEXT,__text) section 00000000 8b 44 24 04 03 44 24 08 c2 08 00
I hope these bytes do what you want!
Edit: perhaps more useful, I just did the same in C:
__attribute__((__stdcall__)) int f(int a, int b) { return a + b; }
Compiled with -Oz and -fomit-frame-pointer , it generates exactly the same code (well, functionally equivalent, anyway):
$ gcc -arch i386 -fomit-frame-pointer -Oz -c -o example.o example.c $ otool -tv example.o example.o: (__TEXT,__text) section _f: 00000000 movl 0x08(%esp),%eax 00000004 addl 0x04(%esp),%eax 00000008 retl $0x0008
Machine Code Output:
$ otool -t example.o example.o: (__TEXT,__text) section 00000000 8b 44 24 08 03 44 24 04 c2 08 00
Will certainly hit the build code manually!
Edit 2:
@Emtucifor asked in the comments below what would happen if an attempt was made to shift 32 bits or more. The split code at the top of this answer (for bytes provided in the original question) can be represented by the following higher-level code:
unsigned int shift_left(unsigned int a, unsigned char b) { if (b > 32) return 0; else return a << b; }
From this logic, itโs pretty easy to notice that if you pass a value greater than 32 as the second parameter of the shift function, you just get 0 back.