This question already has answers here:
How does argument passing and returning values work in C/C++ on x86 at the assembly level? [closed]
(1 answer)
Passing Arguments C -> NASM -> C
(2 answers)
Passing various parameters from C to Assembler
(2 answers)
Closed 1 year ago.
Hi I have already written a program in Assembly 64 bit mode in connection with C, that counts the number of left and right brackets check here:
bits 64
section .data
extern g_left, g_right, g_str
section .text
global count
count:
enter 0,0
mov eax, 0
mov ebx, 0
mov ecx, 0
.back:
cmp [g_str + eax], byte 0
je .out
cmp [g_str + eax], byte '['
jne .right
inc ebx
.right:
cmp [g_str + eax], byte ']'
jne .skip
inc ecx
.skip:
inc eax
jmp .back
.out:
mov [g_l], ebx
mov [g_r], ecx
leave
ret
C code:
#include <stdio.h>
void count();
char g_str[] = "[[[]]]][[32423]][234dsfsdf";
int g_left, g_right;
int main()
{
count();
printf("left = %d and right = %d\n", g_left, g_right);
}
What I want is to use this assembly code but change it a bit so that a function that is called in C with a string as input and just prints the number of brackets. Also, I want it in 32-bit mode this time. It should look like this:
int brackets( char *t_str );
I'm new to assembly and confused on how to change my code, please help me.
Related
This question already has answers here:
Calling C functions from x86 assembly language
(2 answers)
Closed 2 years ago.
I'm doing an assembly x86 program that resolves the determinant of a 2x2 matrix. Well, i've done the driver in C and then I made a function that will be processed in the assembly x86 code.
That's the function in C: int det(int,int,int,int) atribute((_cdecl));
My question is: how do I take these four ints (that i passed like as parameters in that function) in x86? how can I operate with them in the x86 code?
I think that it could be with the stack, but I don't know how.
What you are basically asking is: where are the parameters located, right?
cdecl passes all arguments on the stack, in reverse order. Look up the specs of that calling convention.
So for your function:
int det(int p1, int p2, int p3, int p4);
Your stack will look like this at the beginning of your function:
p4
p3
p2
p1
return address
esp always points to the return address. esp+4 points to p1, esp+8 points to p2 etc..
Please note:
As you are using the cdecl calling convention, you must preserve all registers, except eax, ecx and edx. When you execute ret, all other registers must be the same as they were when you entered the function.
The return value goes in eax.
Here's an example, using NASM syntax. Note that I didn't include a stack frame for the function, because it is a short leaf function, so it is a waste:
; UNTESTED
; int det(int a11, int a12, int a21, int a22)
_det:
mov ecx, [esp + 4]
mov edx, [esp + 12]
imul ecx, edx
mov eax, [esp + 8]
mov edx, [esp + 16]
imul eax, edx
sub ecx, eax
mov eax, ecx
ret
This question already has answers here:
Why can't I move directly a byte to a 64 bit register?
(2 answers)
How do AX, AH, AL map onto EAX?
(6 answers)
Subtracting two characters
(1 answer)
Closed 2 years ago.
I'm trying to re-write the function strcmp in assembly.
I wrote this code:
global _ft_strcmp
section .text
_ft_strcmp:
mov rax, 0
mov rdx, -1
_loop:
inc rdx
mov dh, BYTE[rsi + rdx]
mov al, BYTE[rdi + rdx]
cmp dh, al
je _loop
jmp _exit
_exit:
sub dh, al
mov rax, dh
ret
main.c:
#include <stdio.h>
#include <string.h>
int ft_strcmp(char *s1, char *s2);
int main()
{
printf("|-%d-||-%d-|\n",ft_strcmp("mehdi", "Mehdi"), strcmp("mehdi", "Mehdi"));
return (0);
}
when I compile the file ft_strcmp.s I get this error:
test nasm -f macho64 ft_strcmp.s
ft_strcmp.s:18: error: invalid combination of opcode and operands
EDIT: I'm using Intel x86_64 syntax :)
This question already has answers here:
What is array to pointer decay?
(11 answers)
What kind of C11 data type is an array according to the AMD64 ABI
(1 answer)
What are the calling conventions for UNIX & Linux system calls (and user-space functions) on i386 and x86-64
(4 answers)
Closed 2 years ago.
So I have this C file where I am getting two strings of input from stdin and I am trying to pass them to my assembly code and have my assembly code determine if the first string would come after the second string in a dictionary and if so then return a 1.
#include <stdio.h>
extern int stringcheck(char *s1, char *s2);
int main(){
char s1[30];
fgets(s1, 31, stdin);
char s2[31];
fgets(s2, 31, stdin);
int ret = stringcheck(s1, s2);
if(ret == 1){
printf("True\n");
}
if(ret == 0){
printf("False\n");
}
return 0;
}
In this assembly code I tried to load my strings into appropriate registers and then use cmpsb in a loop and have the program jump to 'second' if the carry flag is set to 1. What happens though is that regardless of the string entered the program will always jump to the 'second' block and return 9 so I'm assuming I messed something up with how I prepared the strings to be checked.
global stringcheck
section .text
stringcheck:
; save state of registers and setup stack frame
push rbp
mov rbp, rsp
push rax
push rbx
push rdx
lea rsi, [rbp+60] ; move first arg into rsi
lea rdi, [rbp+30] ; move second arg into rdi
mov rcx, 30 ; set up incrementer
cld
top: cmpsb
jc second
loop top
jmp first
first: pop rdx
pop rbx
pop rax
mov rsp, rbp
pop rbp
mov rax, 1
ret
second: pop rdx
pop rbx
pop rax
mov rsp, rbp
pop rbp
mov rax, 0
ret
I am completing an assignment related to c programming and assembly language. Here is the simple c program :
int multiply(int a, int b) {
int k = 4;
int c,d, e;
c = a*b ;
d = a*b + k*c;
return d;
}
And it's optimised assembly is
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_multiply PROC
mov eax, DWORD PTR _a$[esp-4]
imul eax, DWORD PTR _b$[esp-4]
lea eax, DWORD PTR [eax+eax*4]
ret 0
_multiply ENDP
I want to know the value of eax register after this line of code in assembly
lea eax, DWORD PTR [eax+eax*4]
I know when add integers in assembly, it stores result in the destination. and when we multiply it stores in eax. so if I call the function multiply( 3 , 8 ), the value of eax register after that line should be 120. Am I correct?
lea is "load effective address".
Instruction sets can have some quite complex multi-register address calculation modes that are generally used just for reading and writing data to memory, but lea allows the programmer to get the address that would be accessed by the instruction.
Effectively, it performs the calculation inside the bracket, returns that value - it doesn't access the memory (which is what bracket usually implies).
In this case it is being used as a quick way to multiply by 5, because the rest of the function has been optimised away!
This question already has answers here:
Why does GCC use multiplication by a strange number in implementing integer division?
(5 answers)
The need for parentheses in macros in C [duplicate]
(8 answers)
Closed 5 years ago.
I have written the following C code. But in runtime it gave me incorrect values for the variable sb, so i tried to debug it with GDB and i found out that the assembly code for the int division E(vdes->addr, bs) (#define E(X,Y) X/Y) was completely incomprehensible and seems to be not doing the right thing.
File: main.c
typedef struct virtual_file_descriptor
{
int dfb;
int addr;
} vfd;
vfd vdes;
if(!strcmp(argv[1], "write")){
vdes.dfb = atoi(argv[2]);
vdes.addr = atoi(argv[3]);
vwrite(&vdes, inbuffer, atoi(argv[4]));
}
File: vwrite.c
#define E(X,Y) X/Y
#define bs sizeof(D_Record)*MAX_BLOCK_ENTRIES
int vwrite(vfd *vdes, char *buffer, int size){
if(!vdes)
return -1;
int sb, nb, offset;
sb = E(vdes->addr, bs) + 1; // i did 140/280 => wrong result
offset = vdes->addr - (sb - 1) * bs;
printf("size=%d bs=%d addr=%d sb=%d offset=%d\n\n", size, bs, vdes->addr, sb, offset);
}
The assembly language generated for the int devision was (Which is wrong and doesn't contain any sings of doing an arithmetic division) :
(gdb) n
58 sb = E(vdes->addr, bs) + 1;
(gdb) x/10i $pc
=> 0x80001c3d <vwrite+39>: mov 0x8(%ebp),%eax
0x80001c40 <vwrite+42>: mov 0x4(%eax),%eax
0x80001c43 <vwrite+45>: shr $0x2,%eax
0x80001c46 <vwrite+48>: mov $0x24924925,%edx
0x80001c4b <vwrite+53>: mul %edx
0x80001c4d <vwrite+55>: mov %edx,%eax
0x80001c4f <vwrite+57>: shl $0x2,%eax
0x80001c52 <vwrite+60>: add %edx,%eax
0x80001c54 <vwrite+62>: add %eax,%eax
0x80001c56 <vwrite+64>: add $0x1,%eax
0x80001c59 <vwrite+67>: mov %eax,-0x2c(%ebp)
0x80001c5c <vwrite+70>: mov 0x8(%ebp),%eax
0x80001c5f <vwrite+73>: mov 0x4(%eax),%eax
0x80001c62 <vwrite+76>: mov %eax,%edx
I copied the same code sequence to a new standalone file and everything works fine (Correct results and correct assembly code). So i came to wonder why doesn't the first code work ?
File: test.c
#define E(X,Y) X/Y
int main(int argc, char **argv){
int sb = E(atoi(argv[1]), atoi(argv[2]));
return 0;
}
Assembly code generated for previous code (which is a nicely understandable and correct code for doing int devision):
.
.
call atoi
.
call atoi
.
.
0x800005db <main+75>: mov %eax,%ecx
0x800005dd <main+77>: mov %edi,%eax
0x800005df <main+79>: cltd
0x800005e0 <main+80>: idiv %ecx
0x800005e2 <main+82>: mov %eax,-0x1c(%ebp)
Just because you don't see an idiv instruction or that you can't understand the code at first glance doesn't mean that it's incorrect. Compilers optimize divisions by constants by multiplying by a large factor and then dividing by a power of two.
With additional info in the comments, we know that bs used to be defined as sizeof(D_Record)*MAX_BLOCK_ENTRIES. The bug is that the E(vdes->addr, bs) macro expands to vfs->address / sizeof(D_Record) * MAX_BLOCK_ENTRIES, which is equivalent to (vfs->address / sizeof(D_Record)) * MAX_BLOCK_ENTRIES. The solution is to add parentheses in E's definition to group correctly:
#define E(X, Y) ((X)/(Y))
This also adds parentheses around the whole expression to be safe, since you could otherwise run into a similar problem doing foo * E(bar, baz).
In addition, before jumping to disassembly, I'd recommend looking at the preprocessed source, which can be done using cpp or gcc -E (or clang -E).
The original question had
#define bs 280
It was later changed to:
#define bs sizeof(D_Record)*MAX_BLOCK_ENTRIES
To avoid issues using bs in other expressions, this should be
#define bs (sizeof(D_Record)*MAX_BLOCK_ENTRIES)
The define for E should be:
#define E(X,Y) ((X)/(Y))
The generated assembly code appears to be based on
#define bs sizeof(D_Record)*MAX_BLOCK_ENTRIES
#define E(X,Y) X/Y
... E(vdes->addr, bs) ...
So divide by 28 using shift and multiply, then multiply by 10.
mov 0x4(%eax),%eax ;eax = dividend
shr $0x2,%eax ;eax = dividend/4 (pre shift)
mov $0x24924925,%edx ;edx = multiply constant
mul %edx ;edx = dividend/28 (no post shift)
mov %edx,%eax ;eax = (dividend/28)*10
shl $0x2,%eax
add %edx,%eax
add %eax,%eax
For the eax = edx*10 sequence, I'm not sure why lea wasn't used:
lea (%edx,%edx,2),eax ;eax = edx*5
add %eax,%eax ;eax = edx*10
Link to prior thread with an explanation how divide by constant is converted into multiply and shifts.
Why does GCC use multiplication by a strange number in implementing integer division?