I'm developing with VS 2012, under 64 bit OS but output executable is 32 bit. Recently I was fiddling with swap algorithm. I did achieve it on C by;
void swap(int *p1, int *p2)
{
*p1 = *p1 + *p2;
*p2 = *p1 - *p2;
*p1 = *p1 - *p2;
}
But I also want to do that with inline assembly (__asm). I tried with these codes;
void aswap(int *p1, int *p2)
{
__asm {
mov ebx, p1
mov ecx, p2
mov p1, ecx
mov p2, ebx
}
}
and test the aswap() with these codes;
int a = 10;
int b = 200;
// print out the initial values
printf("%x(%d) %x(%d)\n", &a, a, &b, b);
aswap(&a, &b);
// finally print out the swapped values
printf("%x(%d) %x(%d)\n", &a, a, &b, b);
but the individual addresses and (consequently) the values are not changes.
Please help me. Thanks in advance.
Update 1: #ouah
I've tested the swap() with these codes;
#include <limits>
int a = INT_MAX;
int b = INT_MAX - 1;
...
and here is my screenshot. Did I do something illegal with the memory?
The classic way to do this is to do an inline swap with several XOR operations. Assuming you have one pointer in EAX and the other in EBX the code would be:
XOR EAX, EBX
XOR EBX, EAX
XOR EAX, EBX
The result is that what was in EAX is now in EBX, and what was in EBX is now in EAX. Follow the bouncing bits to figure out how this works (and it's done entirely in registers, requiring no additional memory).
Share and enjoy.
Related
I am writing a small ASM/C-Program for calculating the number of dividers of a number. I got the following C function:
#include <stdio.h>
extern void getDivisorCounter(int value, int* result);
int main(int argc, char** argv) {
int number;
printf("Please insert number:\n");
scanf("%d", &number);
int* result;
getDivisorCounter(number, result);
printf("amount of div: %d\n", *result);
return 0;
}
where I receive a result from the following assembler programm:
section .text
global getDivisorCounter
getDivisorCounter:
push ebp
mov ebp, esp
mov ecx, [ebp+8]
mov eax, 0
push ebx
for_loop:
mov ebx, ecx
jmp checking
adding:
add ebx, ecx
checking:
cmp ebx, [ebp+8]
jg looping
jl adding
inc eax
looping:
loop for_loop
mov [ebp+12], eax
pop ebx
pop ebp
ret
From Debugging, I know, that I end up with the right value in eax. But somehow I cannot get it to be printed by my C programm.
Could you give me a hint on how to solve this?
If neccessary, I am using NASM and GCC.
You do not need a pointer for this. Anyway, if you (or the assignment) insist, you must 1) initialize said pointer on the C side and 2) write through that pointer on the asm side.
E.g.
int value;
int* result = &value;
and
mov ecx, [ebp+12]
mov [ecx], eax
If you must use a pointer, this does not mean you need to create an extra pointer variable. You can just pass the address of a variable of proper type. This would eliminate the risk of missing memory allocation.
Missing memory allocation is the reason for your problem. result does not point to valid memory.
Instead of
int val;
int *result = &val; // <<== note the mandatory initialization of your pointer.
getDivisorCounter(number, result);
printf("amount of div: %d\n", val);
you could use this:
int result;
getDivisorCounter(number, &result);
printf("amount of div: %d\n", result);
I'd like to start converting a little nasm project {synth.asm, synth_core.nh} to c to learn a little bit more about that little soft-synthesizer.
Problem is my asm knowledge is very very rusty, I'm wondering where to start off. I thought maybe one decompiler could help me out but I haven't found anything open-source able to convert these simple nasm listings to c.
Another alternative would be doing the conversion asm->c manually but I'm struggling to understand one of the most simplest functions :(
ie:
;distortion_machine
;---------------------------
;float a
;float b
;---------------------------
;ebp: distort definition
;edi: stackptr
;ecx: length
section distcode code align=1
distortion_machine:
pusha
add ecx, ecx
.sampleloop:
fld dword [edi]
fld dword [ebp+0]
fpatan
fmul dword [ebp+4]
fstp dword [edi]
scasd
loop .sampleloop
popa
add esi, byte 8
ret
broken attempt:
void distortion_machine(???) { // pusha; saving all registers
int ecx = ecx+ecx; // add ecx, ecx; this doesn't make sense
while(???) { // .sampleloop; what's the condition?
float a = [edi]; // fld dword [edi]; docs says edi is stackptr, what's the meaning?
float b = [ebp+0]; // fld dword [ebp+0]; docs says ebp is distort definition, is that an input parameter?
float c = atan(a,b); // fpatan;
float d = c*[ebp+4]; // fmul dword [ebp+4];
// scasd; what's doing this instruction?
}
return ???;
// popa; restoring all registers
// add esi, byte 8;
}
I guess the above nasm listing is a very simple loop distorting a simple audio buffer but I don't understand which ones are the inputs and which ones are the outputs, I don't even understand the loop conditions :')
Any help with the above routine and how to progress with this little educational project would be really appreciated.
There's a bit of guesswork here:
;distortion_machine
;---------------------------
;float a << input is 2 arrays of floats, a and b, successive on stack
;float b
;---------------------------
;ebp: distort definition << 2 floats that control distortion
;edi: stackptr << what it says
;ecx: length << of each input array (a and b)
section distcode code align=1
distortion_machine:
pusha ; << save all registers
add ecx, ecx ; << 2 arrays, so double for element count of both
.sampleloop:
fld dword [edi] ; << Load next float from stack
fld dword [ebp+0] ; << Load first float of distortion control
fpatan ; << Distort with partial atan.
fmul dword [ebp+4] ; << Scale by multiplying with second distortion float
fstp dword [edi] ; << Store back to same location
scasd ; << Funky way to incremement stack pointer
loop .sampleloop ; << decrement ecx and jump if not zero
popa ; << restore registers
add esi, byte 8 ; << See call site. si purpose here isn't stated
ret
It's a real guess, but esi may be a separate argument stack pointer, and the addresses of a and b have been pushed there. This code ignores them by making assumptions about the data stack layout, but it still needs to remove those pointers from the arg stack.
Approximate C:
struct distortion_control {
float level;
float scale;
};
// Input: float vectors a and b stored consecutively in buf.
void distort(struct distortion_control *c, float *buf, unsigned buf_size) {
buf_size *= 2;
do { // Note both this and the assembly misbehave if buf_size==0
*buf = atan2f(*buf, c->level) * c->scale;
++buf;
} while (--buf_size);
}
In a C re-implementation, you'd probably want to be more explicit and fix the zero-size buffer bug. It wouldn't cost much:
void distort(struct distortion_control *c, float *a, float *b, unsigned size) {
for (unsigned n = size; n; --n, ++a) *a = atan2f(*a, c->level) * c->scale;
for (unsigned n = size; n; --n, ++b) *b = atan2f(*b, c->level) * c->scale;
}
The following C code will result in passing 0xFFFFFFFFFFFFFFFF to malloc() instead of the expected 0, when compiled for x64 by Visual Studio 2013:
#include <stdlib.h>
int main(int argc, char *argv[]) {
int x = -1;
void *p = malloc(x + 1);
}
Opening the disassembly view reveals this strange snippet (Debug configuration, although Release is functionally the same):
; int x = -1;
mov dword ptr [x],0FFFFFFFFh
; void *p = malloc(x + 1);
mov eax,dword ptr [x]
add eax,1
mov eax,eax
mov rcx,0FFFFFFFFFFFFFFFFh
cmovb rax,rcx
mov rcx,rax
call qword ptr [__imp_malloc (07F79C80B228h)]
mov qword ptr [p],rax
Casting to size_t won't change anything, but storing the result to a temporary variable and then passing that to malloc() will.
Strangely, this does not happen when calling any other function similarly declared:
void * __cdecl foo(size_t y) {
return NULL;
}
int main(int argc, char *argv[]) {
int x = -1;
void *p = foo(x + 1);
}
In this case, the correct code is generated (note the missing cmovb stuff):
; int x = -1;
mov dword ptr [x],0FFFFFFFFh
; void *p = foo(x + 1);
mov eax,dword ptr [x]
inc eax
cdqe
mov rcx,rax
call foo (07F6AB84100Ah)
mov qword ptr [p],rax
I hesitate to call this a code generation bug. I must assume it's something I'm missing. However, I've never seen this before and it certainly produces incorrect behavior.
Why is this happening?
It's a safeguard against integer overflow (as referenced in the comments here).
If the value passed to malloc is the result of an integer overflow (signed or unsigned), rather than letting the program allocate less memory than the compiler thinks it expected, it maxes out the expression and attempts to allocate that.
I'm very new to assembly and trying to learn myself.
So far, I've learned that, depending on the number of arguments passed from caller to callee, if there are only a few number of arguments to pass, in stead of push / pop operations, only some specific registers are used.
For example, when passing arguments to a swap function void asm_swap(int *x, int *y), the C compiler uses registers rcx and rdx registers to pass the addresses of the variables (no return value needed in this case). Switching from _cdecl to _fastcall didn't make any difference.
For another function int asm_fact(int x), that is to compute the factorial of x, C compiler uses rcx to pass the value of x, and rax to return the computed factorial. Again, switching from _cdecl to _fastcall didn't make any difference.
Connected to the issue, I have two questions:
Can I deduce an assertion that, whenever I compile the same code, caller will definitely use the same registers for sending and receiving data?
Is there a way to select specific registers as a tool to pass variables (say, for the function asm_fact, I'd prefer to use the rdx to hold the value of x, rather than rcx?
System: Windows 10 (64), VS-2013.
Sample code:
file "main.c"
#include <stdlib.h>
#include <stdio.h>
extern void asm_swap();
extern signed long long int asm_fact();
typedef signed long long int sint64;
sint64 fact_sint64(sint64 n) {
sint64 ret = (sint64)1;
if (n > (sint64)1) {
while (n > (sint64)1) {
ret *= n--;
}
}
return (ret);
}
void swap_sint64(sint64 *a, sint64 *b) {
sint64 t = *a;
*a = *b;
*b = t;
}
int main(void) {
sint64 x, y;
x = 8;
y = 3;
printf("(initial) -> x = %lli y = %lli\n\n", x, y);
swap_sint64(&x, &y);
printf("(swap in c) -> x = %lli y = %lli\n\n", x, y);
asm_swap(&x, &y);
printf("(swap in asm) -> x = %lli y = %lli\n\n", x, y);
y = fact_sint64(x);
printf("(fact in c) -> fact(%lli) = %lli\n\n", x, fact_sint64(x));
y = asm_fact(x);
printf("(fact in asm) -> fact(%lli) = %lli\n\n", x, y);
getchar();
return (0);
}
file "Assembly.asm64"
.data
.code
asm_swap proc
mov r8, [rcx]
mov r9, [rdx]
mov [rcx], r9
mov [rdx], r8
ret
asm_swap endp
asm_fact proc
mov rax, 1
cmp rcx, 1
jle $exit#fact
$loop#fact:
imul rax, rcx
dec rcx
cmp rcx, 1
jg $loop#fact
$exit#fact:
ret
asm_fact endp
end
For windows there is an ABI which specifies
How parameters are passed
Which registers need to be preserved within a call
Msdn:microsoft calling conventions
In order to call as a C function, you should abide by these rules.
You must preserve the non-volatile registers (save and restore them)
I've been playing with DOS real mode assembly for a while and now I want to utilize some routines in a C program. I'm using Turbo C 2.01 and TASM 3.0. I'm however unable to modify a variable passed by address, see the _setval routine below. I don't need/want inline assembly. A simple example:
foo.c
#include <stdio.h>
extern void setval(int *x, int *y);
extern int sum(int x, int y);
int main()
{
int result, a, b;
result = a = b = 0;
setval(&a, &b);
result = a + b;
printf("a+b=%i, a=%i, b=%i\n", result, a, b);
result = 0;
a = 42;
b = 19;
result = sum(a, b);
printf("a+b=%i, a=%i, b=%i\n", result, a, b);
return 0;
}
foortn.asm
public _setval
public _sum
.model small
.stack
.data
.code
_setval proc near
push bp
mov bp, sp
mov word ptr [bp+4], 42
mov word ptr [bp+6], 19
pop bp
ret
endp
_sum proc near
push bp
mov bp, sp
mov ax, word ptr [bp+4]
add ax, word ptr [bp+6]
pop bp
ret
endp
end
I compile it like this:
tcc -c -ms foo.c
tasm /ml foortn.asm
tcc foo.obj foortn.obj
The result is:
a+b=0, a=0, b=0
a+b=61, a=42, b=19
I'm obviously missing something, but what?
Hans, Mark and Bill, thank you very much for your prompt and helpful responses.
Your current code is overwriting the passed pointer. You need to retrieve the pointer and write through it. Something like this:
mov ax, word ptr [bp+4]
mov word ptr [ax], 42
Write this code in C first and look at the assembly code that it generates to get this right.
Try replacing:
mov word ptr [bp+4], 42
mov word ptr [bp+6], 19
with
mov bx, word ptr [bp+4]
mov [bx], 42
mov bx, word ptr [bp+6]
mov [bx], 19
This:
mov word ptr [bp+4], 42
mov word ptr [bp+6], 19
is writing to the stack, not the addresses on the stack. You'll need to read the addresses on the stack, then write to them instead:
mov bx,[bp+4] ; get the address of (a)
mov [bx],42 ; Write to that address
mov bx,[bp+6] ; (b)
mov [bx],19 ; write
I don't know assembler ... but C passes everything by value.
In sum [bp+4] is 42 (or 19); in addsetval [bp+4] is 0xDEADBEEF 0xDECAFBAD (or whatever)