obj-c pass struct pointer to arm assembly function - corruption [duplicate] - objective-c

This question already has an answer here:
return floats to objective-c from arm assembly function
(1 answer)
Closed 6 years ago.
I have a structure in obj-c. I pass a pointer to this structure to an arm assembly function that i've written. When i step into the code i see the pointer get successfully passed in and i can access and modify the values of the structure elements from within my asm code. Life is good - until i return from the asm function. After returning to the calling obj-c code the structure values are all hosed. I can't figure out why. Below are the relevant pieces of my code.
struct myValues{ // define my structure
int ptr2A; // pointer to first float
float A;
float B;
float C;
float D;
float E;
float F;
}myValues;
struct myValues my_asm(int ptr2a, float A, float B, float C, float D, float E, float F); // Prototype for the ASM function
…code here to set values of A-F...
float* ptr2A = &myValues.A; //get the memory address where A is stored
myValues.ptr2A = ptr2A; //put that address into myValues.ptr2A and pass to the ASM function
// now call the ASM code
myValues = my_asm(myValues.ptr2A, myValues.A, myValues.B, myValues.C, myValues.D, myValues.E, myValues.F);
Here is relevant part of my asm code:
mov r5, r1 // r1 has pointer to the first float A
vdiv.f32 s3, s0, s0 //this line puts 1.0 in s3 for ease in debugging
vstr s3, [r5] // poke the 1.0 into the mem location of A
bx lr
When i step through the code everything works as expected and i end up with a 1.0 in the memory location for A. But, once i execute the return (bx lr) and return to the calling obj-c code the values in my structure become garbage. I've dug through the ABI and AACPS (as successfully as a novice probably can) but can't get this figured out. What is happening after that "bx lr" to wack the structure?
Below is "Rev 1" of my asm code. I removed everything except these lines:
_my_asm:
vdiv.f32 s3, s0, s0 // s3 = 1.0
vstr s3, [r1]
bx lr
Ok, this was solution for me. Below is "Rev 2" of the relevant pieces of my obj-c code. I was conflating passing a pointer with passing a copy of the structure - totally hose. This code just passes a pointer to the first float in my struct...which my asm code picks up from general register r0. Man, i'm hard headed. ;-)
void my_asm2(int myptr); // this is my prototype.
This is where i call the asm2 code from my obj-c code:
my_asm2(&myValues.A);
My asm2 code looks like this:
_my_asm2: ; #simple_asm_function
// r0 has pointer to the first float of my myValues structure
// Add prolog code here to play nice
vdiv.f32 s3, s0, s0 //result S3 = 1.0
vstr s3, [r0] // poking a 1.0 back into the myValues.A value
// Add Epilog code here to play nice
bx lr
So, in summary, i can now pass a pointer to my structure myValues to my ASM code and inside my ASM code i can poke new values back into those memory locations. When i return to my calling obj-c code everything is as expected. Thanks to those who helped me fumble along with this hobby. :-)

The solution here is to simply pass a pointer (that points to the memory location of the first float variable in the structure) to the assembly function. Then, any changes the assembly function makes to those memory locations will be intact upon returning to the calling function. Note that this applies to the situation when you are calling assembly code and want that code to operate on an existing data structure (myValues in this case).

Related

Why does the Rust compiler perform a copy when moving an immutable value?

My intuition must be wrong about moves and copies. I would expect the Rust compiler optimize away moves of an immutable value as a no-op. Since the value is immutable, we can safely reuse it after the move. But Rust 1.65.0 on Godbolt compiles to assembly that copies the value to a new position in memory. The Rust code that I am studying:
pub fn f_int() {
let x = 3;
let y = x;
println!("{}, {}", x, y);
}
The resulting assembly with -C opt-level=3:
; pub fn f_int() {
sub rsp, 88
; let x = 3;
mov dword ptr [rsp], 3
; let y = x;
mov dword ptr [rsp + 4], 3
mov rax, rsp
...
Why does let y = x; result in mov dword ptr [rsp + 4], 3 and mov rax, rsp? Why doesn't the compiler treat y as the same variable as x in the assembly?
(This question looks similar but it is about strings which are not Copy. My question is about integers which are Copy. It looks like what I am describing is not a missed optimization opportunity but a fundamental mistake in my understanding.)
I would not call it a fundamental mistake in your understanding, but there are some interesting observations here.
First, println!() (and the formatting machinery in particular) is surprisingly hard to optimize, due to its design. So the fact that with println!() it was not optimized is not surprising.
Second, it is generally not obvious it is OK to perform this optimization, because it observably make the addresses equivalent. And println!() takes the address of the printed values (and passes them to an opaque function). In fact, Copy types are harder to justify than non-Copy types in that regard, because with Copy types the original variable may still be used after a move while with non-Copy types it is possible that not.
If you change your example like this
pub fn f_int() -> i32 {
let x = 3;
let y = x;
// println!("{}, {}", x, y);
x+y
}
the optimisation takes place
example::f_int:
mov eax, 6
ret
The println!() macro (as well as write!()...) takes references on its parameters and provides the formatting machinery with these references.
Probably, the compiler deduces that providing some functions (that are not inlined) with references requires the data being stored somewhere in memory in order to have an address.
Because the type is Copy, the semantics implies that we have two distinct storages, otherwise, sharing the storage would have been an optimisation for a move operation (not a copy).

Create a CByteArray from a CPointer in Visual Works Smalltalk

Some C function return aCPointer to a C struct.
The C struct is known.
Now i want to put the C struct into a ByteArray. Basically copy the contents of the struct to a ByteArray.
In GemStone/S this can be done with:
CByteArray fromCPointer: aCPointer numBytes: 120.
"this create aCByteArray with the contents of the struct referenced by CPointer (copying only 120 bytes)"
Is there something similar on Visual Works ?
I did not find it yet.
It could be possible to replicate C struct at Visual Works level but is only one struct and it is ok to handle it at low level.
There's only the rather ugly #copyAt:to:size:startingAt: that you can send to a pointer. You need to allocate a ByteArray yourself (make sure it's big enough).
answer := ByteArray new: size.
pointer
copyAt: 0
to: answer
size: size
startingAt: 1.
The other way (ByteArray -> Pointer) would be done using #copyAt:from:size:startingAt:.
This method works for both ByteArray and UninterpretedBytes. If you want to read data from the bytes, UninterpretedBytes may be more helpful as you can send things like #longAt: to read a long from an offset.
If aCPointer points to a struct of char * for example:
struct Names
{char * name;
char * longname;} name;
Then:
(aCPointer at: 0) copyCStringFromHeap. "answer [name]"
(aCPointer at: 1) copyCStringFromHeap. "answer [longname]"
For structs with char * it work nicely not tested with other C types.

Reading binary file into a struct using C++/CLI

I have a problem (and I think it can be resolved easily, but it is driving me crazy). I have checked other posts, but I was not able to find the solution.
I would like to read a binary file into a struct using C++/CLI. The problem is that after reading it, some of the values do not fit with the correct ones. In the example below, all the struct fields are well read until "a" (included) (at around byte 100). From that field, the rest have wrong values. I know that they have wrong values and the source file is right, since I previously used python, and FileStream and BinaryReader from C++/CLI. However, I am not using them anymore, given that I would like to read the binary file into a struct.
In addition, in some cases I also have a value of -1 for variable "size" (size of the file), but not always. I am not sure if it could get a wrong value when the file is too big.
Therefore, my question if you can see something that I cannot, or I am doing something wrong.
struct LASheader
{
unsigned short x;
char y[16];
unsigned char v1;
unsigned char v2;
char y1[68];
unsigned short a;
unsigned long b;
unsigned long c;
unsigned char z;
unsigned short d;
unsigned long e;
}
void main()
{
FILE *ptr = fopen("E:\\Pablo\\file.las", "rb");
//I go at the end of the file to get the size
fseek(ptr, 0L, SEEK_END);
unsigned long long size = ftell(ptr);
struct LASheader lasHeader;
//I want an offset of 6 bytes
fseek(ptr, 6, SEEK_SET);
fread(&lasHeader, sizeof(lasHeader), 1, ptr);
unsigned short a1 = lasHeader.a;
unsigned long b1 = lasHeader.b;
unsigned long c1 = lasHeader.c;
unsigned short d1 = lasHeader.d;
unsigned long e1 = lasHeader.e;
}
Thank you!
Pablo.
There's a couple things here. I'll tackle the direct problem first.
You didn't say how this binary format was being written, but I think it's an alignment issue.
Without a #pragma pack directive, unsigned long b will align to a 4-byte boundary. Struct members x through a are 90 bytes total, so two padding bytes are inserted between a and b so that b is aligned properly.
To fix the alignment, you can surround the struct with #pragma pack(push, 1) and #pragma pack(pop).
Second, a more overall issue:
You called this C++/CLI code, and you tagged it C++/CLI, but you're not actually using any managed features in this code. Also, you said you have some C# code that works using BinaryReader, and BinaryReader works fine in C++/CLI, so you technically already had a C++/CLI solution in-hand.
If the rest of your C++/CLI project is this way (not using managed code), consider switching your project to C++, or perhaps splitting it. If your project is largely making use of managed code, then I would strongly consider using BinaryReader instead of fopen to read this data.

ASM 8086 : Reading the value of a variable is different from the value assigned to the variable

I'm writing a little program in Assembly 8086 and I have to use variables.
So I have a variable that is defined in the data segment :
myVar BYTE 3,0
Afterwards in my code I have to acces the variable and use it's value. But the program did not work like expected. So I searched the error in my code and I found that when I acces "myVar", the value is different from the value I assigned to it.
When I print the contents of "myVar" it prints 173 instead of 3 :
xor dx, dx
mov dl, myVar
push dx
CALL tprint
"tprint" is a function I wrote, that will display the number passed as argument via the stack. So in this case it will print the content of the DX register.
When I put 3 in dx and then print it, it prints 3, so "tprint" works fine :
xor dx, dx
mov dl, 3
push dx
CALL tprint
So the problem is that when I move the contents of the variable "myVar" in the DL register, the wrong value is put in DL (another value than the value assigned to "myVar") :
xor dx, dx
mov dl, myVar ; DL != 3 --> why???
I really don't understand this behaviour, I searched a lot of sites and they all do it this way, why does it works fine for them and not for me?
Remark : The "tprint" function is a function for printing signed numbers using two's complement method.
Thanks for your help!
When you move a value from a register, you want to use brackets to move the actual value and not the memory address. So for
mov dl, myVar
you're likely moving just the pointer instead of the value.
See this link

ROL / ROR on variable using inline assembly only in Objective-C [duplicate]

This question already has answers here:
ROL / ROR on variable using inline assembly in Objective-C
(2 answers)
Closed 9 years ago.
A few days ago, I asked the question below. Because I was in need of a quick answer, I added:
The code does not need to use inline assembly. However, I haven't found a way to do this using Objective-C / C++ / C instructions.
Today, I would like to learn something. So I ask the question again, looking for an answer using inline assembly.
I would like to perform ROR and ROL operations on variables in an Objective-C program. However, I can't manage it – I am not an assembly expert.
Here is what I have done so far:
uint8_t v1 = ....;
uint8_t v2 = ....; // v2 is either 1, 2, 3, 4 or 5
asm("ROR v1, v2");
the error I get is:
Unknown use of instruction mnemonic with unknown size suffix
How can I fix this?
A rotate is just two shifts - some bits go left, the others right - once you see this rotating is easy without assembly. The pattern is recognised by some compilers and compiled using the rotate instructions. See wikipedia for the code.
Update: Xcode 4.6.2 (others not tested) on x86-64 compiles the double shift + or to a rotate for 32 & 64 bit operands, for 8 & 16 bit operands the double shift + or is kept. Why? Maybe the compiler understands something about the performance of these instructions, maybe the just didn't optimise - but in general if you can avoid assembler do so, the compiler invariably knows best! Also using static inline on the functions, or using macros defined in the same way as the standard macro MAX (a macro has the advantage of adapting to the type of its operands), can be used to inline the operations.
Addendum after OP comment
Here is the i86_64 assembler as an example, for full details of how to use the asm construct start here.
First the non-assembler version:
static inline uint32 rotl32_i64(uint32 value, unsigned shift)
{
// assume shift is in range 0..31 or subtraction would be wrong
// however we know the compiler will spot the pattern and replace
// the expression with a single roll and there will be no subtraction
// so if the compiler changes this may break without:
// shift &= 0x1f;
return (value << shift) | (value >> (32 - shift));
}
void test_rotl32(uint32 value, unsigned shift)
{
uint32 shifted = rotl32_i64(value, shift);
NSLog(#"%8x <<< %u -> %8x", value & 0xFFFFFFFF, shift, shifted & 0xFFFFFFFF);
}
If you look at the assembler output for profiling (so the optimiser kicks in) in Xcode (Product > Generate Output > Assembly File, then select Profiling in the pop-up menu as the bottom of the window) you will see that rotl32_i64 is inlined into test_rotl32 and compiles down to a rotate (roll) instruction.
Now producing the assembler directly yourself is a bit more involved than for the ARM code FrankH showed. This is because to take a variable shift value a specific register, cl, must be used, so we need to give the compiler enough information to do that. Here goes:
static inline uint32 rotl32_i64_asm(uint32 value, unsigned shift)
{
// i64 - shift must be in register cl so create a register local assigned to cl
// no need to mask as i64 will do that
register uint8 cl asm ( "cl" ) = shift;
uint32 shifted;
// emit the rotate left long
// %n values are replaced by args:
// 0: "=r" (shifted) - any register (r), result(=), store in var (shifted)
// 1: "0" (value) - *same* register as %0 (0), load from var (value)
// 2: "r" (cl) - any register (r), load from var (cl - which is the cl register so this one is used)
__asm__ ("roll %2,%0" : "=r" (shifted) : "0" (value), "r" (cl));
return shifted;
}
Change test_rotl32 to call rotl32_i64_asm and check the assembly output again - it should be the same, i.e. the compiler did as well as we did.
Further note that if the commented out masking line in rotl32_i64 is included it essentially becomes rotl32 - the compiler will do the right thing for any architecture all for the cost of a single and instruction in the i64 version.
So asm is there is you need it, using it can be somewhat involved, and the compiler will invariably do as well or better by itself...
HTH
The 32bit rotate in ARM would be:
__asm__("MOV %0, %1, ROR %2\n" : "=r"(out) : "r"(in), "M"(N));
where N is required to be a compile-time constant.
But the output of the barrel shifter, whether used on a register or an immediate operand, is always a full-register-width; you can shift a constant 8-bit quantity to any position within a 32bit word, or - as here - shift/rotate the value in a 32bit register any which way.
But you cannot rotate 16bit or 8bit values within a register using a single ARM instruction. None such exists.
That's why the compiler, on ARM targets, when you use the "normal" (portable [Objective-]C/C++) code (in << xx) | (in >> (w - xx)) will create you one assembler instruction for a 32bit rotate, but at least two (a normal shift followed by a shifted or) for 8/16bit ones.