cmp eax, 1
je .L3
cmp eax, 4
je .L4
jmp .L9
.L3:
mov DWORD PTR [ebp-16], 1
jmp .L5
.L4:
mov DWORD PTR [ebp-16], 2
jmp .L5
I need some help figuring out how exactly to convert this to C code. I've tried doing a nested if statement but it converts to
cmp eax, 1
je .L3
cmp eax, 4
je .L3
The code I tried was this
if (var1 != 1)
{
if(var1!=4)
{
var2=1;
}
}
Entire Assembly code for context
push ebp
mov ebp, esp
sub esp, 16
mov DWORD PTR [ebp-4], 4
mov DWORD PTR [ebp-16], 0
mov DWORD PTR [ebp-8], 0
mov eax, DWORD PTR [ebp-4]
cmp eax, 1
je .L3
cmp eax, 4
je .L4
jmp .L9
.L3:
mov DWORD PTR [ebp-16], 1
jmp .L5
.L4:
mov DWORD PTR [ebp-16], 2
jmp .L5
.L9:
mov DWORD PTR [ebp-16], 3
.L5:
mov DWORD PTR [ebp-12], 0
jmp .L6
.L7:
mov eax, DWORD PTR [ebp-12]
add DWORD PTR [ebp-8], eax
add DWORD PTR [ebp-12], 1
.L6:
mov eax, DWORD PTR [ebp-12]
cmp eax, DWORD PTR [ebp-16]
jl .L7
mov eax, 0
leave
ret
That code should be assimilated to:
if (var1 == 1)
goto l3;
else if (var1 == 4) // we use the same value in eax so the same variable is being checked
goto l4;
else goto l9;
l3: var2 = 1; goto l5;
l4: var2 = 2; goto l5;
l9: var2 = 3;
l5: ...
I should use a switch statement, as all the tests depend on the value of the var1 variable (indeed, the value of var1 is evaluated and stored into eax, and this is the value compared all the time) giving:
switch (var1) {
case 1: var2 = 1; break;
case 4: var2 = 2; break;
default: var2 = 3; break;
}
Related
pleasse i need someone to assit me with my assighnment.
q1. Examine the code below and Draw the stack frame after analysing the assembly code when function1, function2 and function3 are called by the main program for a 32-bit system. Figure 2 shows a sample stack frame of a function.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int function1(int x, int y, int z)
{
int result_func1;
result_func1 = x + y + z;
return result_func1;
}
int function2(int x, int y, char* input_string)
{
int result_func2;
char buffer[20];
strcpy(buffer, input_string);
printf("your input string %s is copied in the buffer \n", input_string);
result_func2= x - y;
return result_func2;
}
void function3(int result1, int result2)
{
printf("The result of function 1 is %d\n", result1);
printf("The result of function 1 is %d\n", result1);
}
void function4(void)
{
printf("The function never gets called is \n");
exit(-1);
}
int main(int argc, char* argv[])
{
int result1;
int result2;
result1 = function1(5, 10, 15);
result2 = function2(20, 8, argv[1]);
function3(result1, result1);
}
assembly code of the after the analysis:
0x00005555555552c0 <+0>: endbr64
0x00005555555552c4 <+4>: push %rbp
0x00005555555552c5 <+5>: mov %rsp,%rbp
0x00005555555552c8 <+8>: sub $0x20,%rsp
0x00005555555552cc <+12>: mov %edi,-0x14(%rbp)
0x00005555555552cf <+15>: mov %rsi,-0x20(%rbp)
0x00005555555552d3 <+19>: mov $0xf,%edx
0x00005555555552d8 <+24>: mov $0xa,%esi
0x00005555555552dd <+29>: mov $0x5,%edi
0x00005555555552e2 <+34>: callq 0x5555555551c9 <function1>
0x00005555555552e7 <+39>: mov %eax,-0x8(%rbp)
0x00005555555552ea <+42>: mov -0x20(%rbp),%rax
0x00005555555552ee <+46>: add $0x8,%rax
0x00005555555552f2 <+50>: mov (%rax),%rax
0x00005555555552f5 <+53>: mov %rax,%rdx
0x00005555555552f8 <+56>: mov $0x8,%esi
0x00005555555552fd <+61>: mov $0x14,%edi
0x0000555555555302 <+66>: callq 0x5555555551ef <function2>
0x0000555555555307 <+71>: mov %eax,-0x4(%rbp)
0x000055555555530a <+74>: mov -0x8(%rbp),%edx
0x000055555555530d <+77>: mov -0x8(%rbp),%eax
0x0000555555555310 <+80>: mov %edx,%esi
0x0000555555555312 <+82>: mov %eax,%edi
0x0000555555555314 <+84>: callq 0x555555555261 <function3>
0x0000555555555319 <+89>: mov $0x0,%eax
0x000055555555531e <+94>: leaveq
0x000055555555531f <+95>: retq
modidied(actual 32bit assembly code)
function1:
push ebp
mov ebp, esp
mov eax, DWORD PTR [ebp+12]
add eax, DWORD PTR [ebp+8]
add eax, DWORD PTR [ebp+16]
pop ebp
ret
.LC0:
.string "your input string %s is copied in the buffer \n"
function2:
push ebp
mov ebp, esp
push ebx
lea eax, [ebp-28]
sub esp, 44
mov ebx, DWORD PTR [ebp+16]
push ebx
push eax
call strcpy
pop eax
pop edx
push ebx
push OFFSET FLAT:.LC0
call printf
mov eax, DWORD PTR [ebp+8]
mov ebx, DWORD PTR [ebp-4]
sub eax, DWORD PTR [ebp+12]
leave
ret
.LC1:
.string "The result of function 1 is %d\n"
function3:
push ebp
mov ebp, esp
push ebx
sub esp, 12
mov ebx, DWORD PTR [ebp+8]
push ebx
push OFFSET FLAT:.LC1
call printf
mov DWORD PTR [ebp+12], ebx
add esp, 16
mov ebx, DWORD PTR [ebp-4]
mov DWORD PTR [ebp+8], OFFSET FLAT:.LC1
leave
jmp printf
.LC2:
.string "The function never gets called is "
function4:
push ebp
mov ebp, esp
sub esp, 20
push OFFSET FLAT:.LC2
call puts
mov DWORD PTR [esp], -1
call exit
main:
lea ecx, [esp+4]
and esp, -16
push DWORD PTR [ecx-4]
push ebp
mov ebp, esp
push ecx
sub esp, 8
mov eax, DWORD PTR [ecx+4]
push DWORD PTR [eax+4]
push 8
push 20
call function2
pop edx
pop ecx
push 30
push 30
call function3
mov ecx, DWORD PTR [ebp-4]
xor eax, eax
leave
lea esp, [ecx-4]
ret
please i need someone who can assist me with who to start
I'm working on a calculator, and at the part where operations are actually executed, I have a big long switch block that looks something like this (the cases go up linearly starting at 1):
switch(operator) {
case 1:
a = a + b;
break;
case 2:
a = a - b;
break;
...
case 20:
a = sin(a);
break;
I have quite a few operators and functions at this point and testing each case one at a time doesn't seem like it would be the fastest option.
Is there a way to use a table (such as an array of goto labels, or an array of function pointers) so that the "operator" variable would cause the program to jump to the appropriate operation without the program having to test for each of the cases? If so, how would I go about doing this, given the above code?
It can not be faster then switch and I will show you why. Here is my version of your function with switch
void switch_fun(int operator) {
switch(operator) {
case 0:
a = a + b;
break;
case 1:
a = a - b;
break;
case 2:
a = a * b;
break;
}
}
Which translate to this assembler (with comments for non-assembly people)
switch_fun:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi ## copy 'operator'
cmp DWORD PTR [rbp-4], 2 ## compare 'operator' with 2
je .L2 ## if 'operator' is equal to 2 jump to .L2 (few lines below)
cmp DWORD PTR [rbp-4], 0 ## same comparition for 0
je .L4
cmp DWORD PTR [rbp-4], 1 ## and for 1
je .L5
jmp .L6 ## if nothing match jump at the end of the function
.L4:
mov edx, DWORD PTR a[rip]
mov eax, DWORD PTR b[rip]
add eax, edx ## addition, like in case 0:
mov DWORD PTR a[rip], eax
jmp .L3 ## jump at the end
.L5:
mov eax, DWORD PTR a[rip]
mov edx, DWORD PTR b[rip]
sub eax, edx ## subtraction
mov DWORD PTR a[rip], eax
jmp .L3
.L2:
mov edx, DWORD PTR a[rip]
mov eax, DWORD PTR b[rip]
imul eax, edx ## multiplication
mov DWORD PTR a[rip], eax
nop
.L3:
.L6:
nop
pop rbp
ret
It's pretty simple construction and probably impossible to optimize even more, but let's try. Here I have version of this function but with array of addresses to goto labels.
void array_fun(int operator) {
void* labels[] = {&&addition, &&subtraction, &&mul};
goto *labels[operator];
addition:
a = a + b;
goto outer;
subtraction:
a = a - b;
goto outer;
mul:
a = a * b;
outer:
return;
}
Ignoring fact that this code is really unsafe because if operator will be greater then 2 this will crash program but whatever, let's see how this look in assembly.
array_fun:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-36], edi
mov QWORD PTR [rbp-32], OFFSET FLAT:.L8
mov QWORD PTR [rbp-24], OFFSET FLAT:.L9
mov QWORD PTR [rbp-16], OFFSET FLAT:.L10 ## here you eliminated some comparitions
## but add some new 'moves' and calculations, everything below is practically the same like in first function, it's definitely not faster, probably slower then switch
mov eax, DWORD PTR [rbp-36]
cdqe
mov rax, QWORD PTR [rbp-32+rax*8]
nop
jmp rax
.L8:
mov edx, DWORD PTR a[rip]
mov eax, DWORD PTR b[rip]
add eax, edx
mov DWORD PTR a[rip], eax
jmp .L12
.L9:
mov eax, DWORD PTR a[rip]
mov edx, DWORD PTR b[rip]
sub eax, edx
mov DWORD PTR a[rip], eax
jmp .L12
.L10:
mov edx, DWORD PTR a[rip]
mov eax, DWORD PTR b[rip]
imul eax, edx
mov DWORD PTR a[rip], eax
.L12:
nop
pop rbp
ret
TL;DR don't try to optimize switch on integers because it's impossible to do
EDIT: With array of pointers to functions it would be even worse because you will get overhead because of calling a function
I am trying to convert the following C program to inline assembly:
#include <stdio.h>
#include <string.h>
int main()
{
int counter = 0;
int input = 0;
char name[20];
printf("Please input an integer value 1 - 99: ");
scanf("%d", &input);
printf("You entered: %d\n", input);
if (input <= 0)
{
printf("Error, invalid input \n");
}
if (input > 0)
{
printf("Please input name \n");
scanf("%s", name);
for (int i = 1; i <=input; i++)
{
printf("Your name is %s\n", name);
printf("%d\n", i);
}
}
return 0;
}
Here is my attempt at the inline:
.LC0:
.string "please input an interger value 1-99"
.LC1:
.string "%d"
.LC2:
.string "you entered %d"
.LC3:
.string "Error invalid input"
.LC4:
.string "please input name"
.LC5:
.string "%s"
.LC6:
.string "Your name is %s"
main:
push rbp
mov rbp, rsp
sub rsp, 32
mov DWORD PTR [rbp-8], 0
mov DWORD PTR [rbp-12], 0
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
lea rax, [rbp-12]
mov rsi, rax
mov edi, OFFSET FLAT:.LC1
mov eax, 0
call scanf
mov eax, DWORD PTR [rbp-12]
mov esi, eax
mov edi, OFFSET FLAT:.LC2
mov eax, 0
call printf
mov eax, DWORD PTR [rbp-12]
test eax, eax
jg .L2
mov edi, OFFSET FLAT:.LC3
mov eax, 0
call printf
.L2:
mov eax, DWORD PTR [rbp-12]
test eax, eax
jle .L3
mov edi, OFFSET FLAT:.LC4
mov eax, 0
call printf
lea rax, [rbp-32]
mov rsi, rax
mov edi, OFFSET FLAT:.LC5
mov eax, 0
call scanf
mov DWORD PTR [rbp-4], 1
jmp .L4
.L5:
lea rax, [rbp-32]
mov rsi, rax
mov edi, OFFSET FLAT:.LC6
mov eax, 0
call printf
mov eax, DWORD PTR [rbp-4]
mov esi, eax
mov edi, OFFSET FLAT:.LC1
mov eax, 0
call printf
add DWORD PTR [rbp-4], 1
.L4:
mov eax, DWORD PTR [rbp-12]
cmp DWORD PTR [rbp-4], eax
jle .L5
.L3:
mov eax, 0
leave
ret
So I guess my question is, am I on the right track? I find this stuff extremely confusing. It doesn't help that all my instructor sais is that "I am on the right track" so any help would be much appreciated! (Whenever I run this I get an error on the first line complaining about the ".")
Thank you guys! Figured out that the inline was unnecessary and that we were supposed to be doing regular assembly! Really appreciate the help!
So, I am trying to see if there is any difference between using a jump table of function pointers versus a switch statements for performing many, one command operations like these.
This is the code to assembly link i made
Here is my actual code as well
enum code {
ADD,
SUB,
MUL,
DIV,
REM
};
typedef struct {
int val;
} Value;
typedef struct {
enum code ins;
int operand;
} Op;
void run(Value* arg, Op* func)
{
switch(func->ins)
{
case ADD: arg->val += func->operand; break;
case SUB: arg->val -= func->operand; break;
case MUL: arg->val *= func->operand; break;
case DIV: arg->val /= func->operand; break;
case REM: arg->val %= func->operand; break;
}
}
My question is, based on the generated assembly in that link or the code, would there be any difference from making a bunch of small functions to complete the operations in the cases of the switch statement, and making an array of pointers to those functions and calling them with the same enum?
Using gcc x86_64 7.1
void add(Value* arg, Op* func)
{
arg->val += func->operand;
}
static void (*jmptable)(Value*, Op*)[] = {
&add
}
Assembly code paste:
run(Value*, Op*):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov QWORD PTR [rbp-16], rsi
mov rax, QWORD PTR [rbp-16]
mov eax, DWORD PTR [rax]
cmp eax, 4
ja .L9
mov eax, eax
mov rax, QWORD PTR .L4[0+rax*8]
jmp rax
.L4:
.quad .L3
.quad .L5
.quad .L6
.quad .L7
.quad .L8
.L3:
mov rax, QWORD PTR [rbp-8]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rbp-16]
mov eax, DWORD PTR [rax+4]
add edx, eax
mov rax, QWORD PTR [rbp-8]
mov DWORD PTR [rax], edx
jmp .L2
.L5:
mov rax, QWORD PTR [rbp-8]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rbp-16]
mov eax, DWORD PTR [rax+4]
sub edx, eax
mov rax, QWORD PTR [rbp-8]
mov DWORD PTR [rax], edx
jmp .L2
.L6:
mov rax, QWORD PTR [rbp-8]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rbp-16]
mov eax, DWORD PTR [rax+4]
imul edx, eax
mov rax, QWORD PTR [rbp-8]
mov DWORD PTR [rax], edx
jmp .L2
.L7:
mov rax, QWORD PTR [rbp-8]
mov eax, DWORD PTR [rax]
mov rdx, QWORD PTR [rbp-16]
mov esi, DWORD PTR [rdx+4]
cdq
idiv esi
mov edx, eax
mov rax, QWORD PTR [rbp-8]
mov DWORD PTR [rax], edx
jmp .L2
.L8:
mov rax, QWORD PTR [rbp-8]
mov eax, DWORD PTR [rax]
mov rdx, QWORD PTR [rbp-16]
mov ecx, DWORD PTR [rdx+4]
cdq
idiv ecx
mov rax, QWORD PTR [rbp-8]
mov DWORD PTR [rax], edx
nop
.L2:
.L9:
nop
pop rbp
ret
A catchall answer to all these questions: you should measure.
Practically though, I'm betting on the switch version. Function calls have overhead (and they can be hardly inlined in this context), which you could eliminate with labels as values, which is a common compiler extension*, but you should really try all your options and measure if the performance of this piece of code matters to you greatly.
Otherwise, use whatever's most convenient to you.
*a switch is likely to generate a jump table equivalent to what you could compose from labels as values but it could switch between different implementations depending on the particular case values and their number
Can you spot the difference? Trust in compiler (it will do such a micro optimisations much better than you) - and do not forget break statements. Care about algorithm, not about such a small details.
https://godbolt.org/g/sPxse2
Looks like due to branch prediction and bounds checking, using the switch labels as jump points may be up to 20% faster on older systems - newer systems having better branch prediction. Basically, this relies on a compiler extension. You still have the switch, but the switch doesn't fall through to the dispatcher. Instead, each case has its own dispatcher that jumps directly into the case. A number of popular VMs do this.
See here for more info and examples:https://www.cipht.net/2017/10/03/are-jump-tables-always-fastest.html
I wrote this classic function : (in 32-bit mode)
void ex(size_t a, size_t b)
{
size_t c;
c = a;
a = b;
b = c;
}
I call it inside the main as follows :
size_t a = 4;
size_t b = 5;
ex(a,b);
What I was expecting from the assembly code generated when entering the function is something like this :
1-Push the values of b and a in the stack : (which was done)
mov eax,dword ptr [b]
push eax
mov ecx,dword ptr [a]
push ecx
2-Use the values of a and b in the stack :
push ebp
mov ebp, esp
sub esp, 4
c = a;
mov eax, dword ptr [ebp+8]
mov dword ptr [ebp-4], eax
and so on for the other variables.
However, this is what I find when debugging :
push ebp
mov ebp,esp
sub esp,0CCh // normal since it's in debug with ZI option
push ebx
push esi
push edi
lea edi,[ebp-0CCh]
mov ecx,33h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
size_t c;
c = a;
mov eax,dword ptr [a]
mov dword ptr [c],eax
Why is it using the variable a directly instead of calling the value stored in the stack? I don't understand...
The debugger doesn't show the instruction using ebp to access a. The same syntax is permitted when you write inline assembly. Otherwise the reason that dword ptr still appears.
It is easy to get it your preferred way, right click > untick "Show Symbol Names".
Using the assembly output option (right click on file name, properties, ...), I get what you expect from debug assembly output. This could depend on which version of VS you use. For this example, I used VS2005. I have VS2015 on a different system, but didn't try it yet.
_c$ = -8 ; size = 4
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_ex PROC ; COMDAT
push ebp
mov ebp, esp
sub esp, 204 ; 000000ccH
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-204]
mov ecx, 51 ; 00000033H
mov eax, -858993460 ; ccccccccH
rep stosd ;fill with 0cccccccch
mov eax, DWORD PTR _a$[ebp]
mov DWORD PTR _c$[ebp], eax
mov eax, DWORD PTR _b$[ebp]
mov DWORD PTR _a$[ebp], eax
mov eax, DWORD PTR _c$[ebp]
mov DWORD PTR _b$[ebp], eax
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
_ex ENDP
Note this doesn't work, you need to use pointers for the swap to work.
void ex(size_t *pa, size_t *pb)
{
size_t c;
c = *pa;
*pa = *pb;
*pb = c;
}
which gets translated into:
_c$ = -8 ; size = 4
_pa$ = 8 ; size = 4
_pb$ = 12 ; size = 4
_ex PROC ; COMDAT
push ebp
mov ebp, esp
sub esp, 204 ; 000000ccH
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-204]
mov ecx, 51 ; 00000033H
mov eax, -858993460 ; ccccccccH
rep stosd
mov eax, DWORD PTR _pa$[ebp]
mov ecx, DWORD PTR [eax]
mov DWORD PTR _c$[ebp], ecx
mov eax, DWORD PTR _pa$[ebp]
mov ecx, DWORD PTR _pb$[ebp]
mov edx, DWORD PTR [ecx]
mov DWORD PTR [eax], edx
mov eax, DWORD PTR _pb$[ebp]
mov ecx, DWORD PTR _c$[ebp]
mov DWORD PTR [eax], ecx
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
_ex ENDP