In asm file1 I try to export a variable and use it in another.
I've tried to find how to do that from manuals & tutorials, but no success.
So, how can I share a global variable between asm files?
// File 1
// Here is saved value of a register (r10) to a variable.
.section .data
.global r10_save
r10_save_addr: .word r10_save
.section .text
ldr r13, =r10_save_addr // Load address for the global variable to some reg (r13)
str r13, [r10] // Save r13 to global variable
// File 2
// Here the intention is to use the variable (that should have r10 value stored).
.section .data
str_r10:
.asciz "r10 = 0x"
strlen_r10 = .-str_r10
.section .text
/* Here I want to use the reference of a variable
which has got its value in other file.
*/
mov r0, $1 //
ldr r1, =str_r10 // address of text string
ldr r2, =strlen_r10 // number of bytes to write
mov r7, $4 //
swi 0
You can use extern to get the value of global varibles:
// File 2
// Here the intention is to use the variable (that should have r10 value stored).
.section .data
str_r10:
.asciz "r10 = 0x"
strlen_r10 = .-str_r10
.section .text
/* Here I want to use the reference of a variable
which has got its value in other file.
*/
.extern r10_save // or EXTERN DATA(r10_save)
mov r0, $1 //
ldr r1, =str_r10 // address of text string
ldr r2, =strlen_r10 // number of bytes to write
mov r7, $4 //
swi 0
Then you can access r10_save in the second file too.
Related
Consider this code snippet:
__asm volatile (
" MOVW R0, #0x0000 \n\t"
" MOVT R0, #0x3004 \n\t"
" LDRSH R1, [R0, #12] \n\t"
⋮
)
This is the hard-coded way for loading what's stored at address 0x30040000 + 12 into R1.
I understand I can use a list of input and output variables and a clobber list. So if I use something like this:
int16_t localVar = 10;
__asm volatile (
" <some code with %[lv]> \n\t"
" LDRSH R1, ??? \n\t"
⋮
: [lv] "r" (localVar)
⋮
)
What do I need to replace <some code with %[lv]> and/or the question marks with so that I end up with value 10 in register R1? I generally don't know how to do this. It would be great to learn the most efficient way for ARM-v7 in terms of execution time needed.
I am using a MSP 432 and have to create an assembly functions in C. I tried creating the functions using __asm void PendSV_Handler{}. But that does not work and says Expected an Identifier.
Also, I am trying to run this assembler command cpsid i but it says CPSID is undefined but CPSIE i works. I am a bit confused at this point. I am fairly new to this and I am still learning.
Below is the code I am trying to make assembly. I try making the function assembly by doing __asm void PendSV_handler.
I was not sure if it would be easier to just create a asm. file with these instructions.
OSThread *volatile OS_curr;
OSThread *volatile OS_next;
void PendSV_Handler(void){
__asm__("cpsid i"
//if(OS_curr != (OSThread *)0)
"ldr r0, =OS_curr"
"ldr r0, [r0]"
"cbz r0, PendSV_restore");
// Push r4 - r11
__asm__("PUSH {r4-r11}"
"ldr r1, =OS_curr"
"ldr r1, [r1]"
// OS_curr -> sp = sp;
"str sp, [r1]");
PendSV_restore
// sp=OS_next -> sp;
__asm__("ldr r0, =OS_next;"
"ldr r0, [r0]"
"ldr r0, [r0]"
"str sp, [r13]");
// OS_curr = OS_next;
__asm__("ldr r0, =OS_next"
"ldr r1, [pc, 0xc]"
"ldr r0, =OS_curr"
"str r0, [r1]"
//Pop r4-r11
"POP {r4-r11}"
// __enable_interrupts();
"cpsie i"
//return to next thread
"bx r14");
}
Inline assembler syntax is not redefined in the C programming language, and its support and syntax is compiler specific. In GCC:
void PendSV_Handler(void)
{
__asm__("cpsid i");
//if(OS_curr != (OSThread *)0)
__asm__("ldr r0, =OS_curr");
__asm__("ldr r0, [r0]");
__asm__("cbz r0, PendSV_restore");
// Push r4 - r11
__asm__("PUSH {r4-r11}");
__asm__("ldr r1, =OS_curr");
__asm__("ldr r1, [r1]");
// OS_curr -> sp = sp;
__asm__("str sp, [r1]");
PendSV_restore:
// sp=OS_next -> sp;
__asm__("ldr r0, =OS_next;");
__asm__("ldr r0, [r0]");
__asm__("ldr r0, [r0]");
__asm__("str sp, [r13]");
// OS_curr = OS_next;
__asm__("ldr r0, =OS_next");
__asm__("ldr r1, [pc, 0xc]");
__asm__("ldr r0, =OS_curr");
__asm__("str r0, [r1]");
//Pop r4-r11
__asm__("POP {r4-r11}");
// __enable_interrupts();
__asm__("cpsie i");
//return to next thread
__asm__("bx r14");
}
Referencing
Inline assembler syntax is not redefined in the C programming language
I did in the past for a university project
inline void function(param1,param2)
{
asm volatile ("param1");
asm volatile ("param2");
}
But, if u are working on ARM, look at the instruction set to see whitch commands are possible
As an example:
If you want to write some timing critical stuff, that needs to be in the written order you could do something like this
inline void COLOUR_GLCD_write_address_data(uint8_t address, uint16_t data)
{
asm volatile ("DMB");
*(volatile uint16_t*)LCD_CMD_ADDRESS = address;
asm volatile ("DMB");
*(volatile uint16_t*)LCD_DATA_ADDRESS = data;
}
This was for sending data to an external lcd via the BUS Interface on an Atmel SAME70.
Hope that helped =)
I'm trying to get the size of a Direct2D Bitmap and getting an immediate crash.
// props and target etc all set up beforehand.
CComPtr<ID2D1Bitmap> &b;
target->CreateBitmap(D2D1::SizeU(1024,1024), frame.p_data, 1024* 4, &props, &b));
D2D_SIZE_U sz = b->GetPixelSize(); // Crashes here.
All other operations using the bitmap (including drawing it) work correctly. It's just returning the size that seems to be the problem.
Based on a articles like this by Rudy V, my suspicion is that it's some incompatibility with C++Builder 2010 and how COM functions return 64-bit structures. http://rvelthuis.de/articles/articles-convert.html
The Delphi declaration of GetPixelSize looks like this: (from D2D1.pas)
// Returns the size of the bitmap in resolution dependent units, (pixels).
procedure GetPixelSize(out pixelSize: TD2D1SizeU); stdcall;
... and in D2D1.h it's
//
// Returns the size of the bitmap in resolution dependent units, (pixels).
//
STDMETHOD_(D2D1_SIZE_U, GetPixelSize)(
) CONST PURE;
Can I fix this without rewriting the D2D headers?
All suggestions welcome - except upgrading from C++Builder 2010 which is more of a task than I'm ready for at the moment.
„getInfo“ is a function derived from Delphi code, which can work around.
void getInfo(void* itfc, void* info, int vmtofs)
{
asm {
push info // pass pointer to return result
mov eax,itfc // eax poionts to interface
push eax // pass pointer to interface
mov eax,[eax] // eax points to VMT
add eax,vmtofs // eax points rto address of virtual function
call dword ptr [eax] // call function
}
}
Disassembly of code generated by CBuilder, which results in a crash:
Graphics.cpp.162: size = bmp->GetSize();
00401C10 8B4508 mov eax,[ebp+$08]
00401C13 FF7004 push dword ptr [eax+$04]
00401C16 8D55DC lea edx,[ebp-$24]
00401C19 52 push edx
00401C1A 8B4D08 mov ecx,[ebp+$08]
00401C1D 8B4104 mov eax,[ecx+$04]
00401C20 8B10 mov edx,[eax]
00401C22 FF5210 call dword ptr [edx+$10]
00401C25 8B4DDC mov ecx,[ebp-$24]
00401C28 894DF8 mov [ebp-$08],ecx
00401C2B 8B4DE0 mov ecx,[ebp-$20]
00401C2E 894DFC mov [ebp-$04],ecx
„bmp“ is declared as
ID2D1Bitmap* bmp;
Code to call „getInfo“:
D2D1_SIZE_F size;
getInfo(bmp,&pf,0x10);
You get 0x10 (vmtofs) from disassembly line „call dword ptr [edx+$10]“
You can call „GetPixelSize“, „GetPixelFormat“ and others by calling „getInfo“
D2D1_SIZE_U ps;// = bmp->GetPixelSize();
getInfo(bmp,&ps,0x14);
D2D1_PIXEL_FORMAT pf;// = bmp->GetPixelFormat();
getInfo(bmp,&pf,0x18);
„getInfo“ works with methods „STDMETHOD_ ... CONST PURE;“, which return a result.
STDMETHOD_(D2D1_SIZE_F, GetSize)(
) CONST PURE;
For this method CBuilder generates malfunctional code.
In case of
STDMETHOD_(void, GetDpi)(
__out FLOAT *dpiX,
__out FLOAT *dpiY
) CONST PURE;
the CBuilder code works fine, „getDpi“ results void.
I'm still playing with retro programming in turbo C for MS-DOS, and I found some trounble using variables.
If I define some variables at the start of the assembly code (in BSS or DATA), and try to use them inside the assembly function, most of the time these variables are deleted, or end up containing random data.
I learned a bit of assembly for the game boy :) and variables always worked well and never were deleted or modified, I guess x86 asm is different.
Then I tried this using inline assembly and it was a bit better, there is just one variable (width) not working.
void draw_map_column(MAP map, TILE *t){
word *tiledata = &t->data;
int *mapdata = map.data;
int width = map.width<<1;
word tile_offset = 0;
word map_offset = 0;
word screen_offset = 0;
asm{
push ds
push di
push si
mov dx,12 //column
lds bx,[tiledata]
lds si,ds:[bx] //ds:si data address
mov [tile_offset],ds
mov [tile_offset+2],si
les bx,[mapdata]
mov ax,es:[bx]
mov cl,8
shl ax,cl
add si,ax
mov di,screen_offset //es:di screen address
}
loop_tile:
asm{
mov ax,0A000h
mov es,ax
mov ax,16
}
copy_tile:
asm{
mov cx,8
rep movsw
add di,320-16
dec ax
jnz copy_tile
mov ds,[tile_offset]
mov si,[tile_offset+2]
mov ax,map_offset
add ax,[width] //"width" does never contain the value stored at the start
mov map_offset,ax
les bx,[mapdata]
add bx,ax
mov ax,es:[bx]
mov cl,8
shl ax,cl
add si,ax
dec dx
jnz loop_tile
pop si
pop di
pop ds
}
}
Just note the "witdh" variable which is not working at all, if I replace it with a number (40), the code just works as expected (this draws a column of tiles using a map array, and some tiles stored in ram).
I guess it has something to do with the push/pop etc, and something is not set as it should.
Also what happens in pure assembly? none of the variables were working. I defined them as DW and also added:
push bp
mov bp,sp
;function
mov sp,bp
pop bp
Thanks.
Well once again thanks a lot, next time I'll be more patient before asking.
Just in case this is useful for someone, I had defined a variable using the wrong size.
There are other things that can be improved, but that's another question.
Variable "tileoffset" holds a 32 bit address, so it must be a "dword", not a "word". Then the function should be like this:
void draw_map_column(MAP map, TILE *t){
word *tiledata = &t->data;
int *mapdata = map.data;
int width = map.width<<1;
dword tile_offset = 0; //changed to dword to store 32 bit address
word map_offset = 0;
word screen_offset = 0;
asm{
push ds
push di
push si
mov dx,12 //column
lds bx,[tiledata]
lds si,ds:[bx] //ds:si data address
mov word ptr[tile_offset],ds //store a word
mov word ptr[tile_offset+2],si
les bx,[mapdata]
mov ax,es:[bx]
mov cl,8
shl ax,cl
add si,ax
mov di,screen_offset //es:di screen address
}
loop_tile:
asm{
mov ax,0A000h
mov es,ax
mov ax,16
}
copy_tile:
asm{
mov cx,8
rep movsw
add di,320-16
dec ax
jnz copy_tile
mov ds,word ptr[tile_offset] //read a word to the register
mov si,word ptr[tile_offset+2]
mov ax,map_offset
add ax,[width]
mov map_offset,ax
les bx,[mapdata]
add bx,ax
mov ax,es:[bx]
mov cl,8
shl ax,cl
add si,ax
dec dx
jnz loop_tile
pop si
pop di
pop ds
}
Consider the following Objective C interface definition
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
#property NSObject* myprop;
#end
The assembly generated for ARMv7 by Xcode 5 for [MyClass myprop] looks like
.code 16 # #"\01-[MyClass myprop]"
.thumb_func "-[MyClass myprop]"
"-[MyClass myprop]":
Lfunc_begin0:
.cfi_startproc
# BB#0:
sub sp, #8
#DEBUG_VALUE: -[MyClass myprop]:self <- undef
#DEBUG_VALUE: -[MyClass myprop]:_cmd <- undef
str r0, [sp, #4]
str r1, [sp]
ldr r0, [sp, #4]
movw r2, :lower16:(_OBJC_IVAR_$_MyClass.myprop-(LPC0_0+4))
movt r2, :upper16:(_OBJC_IVAR_$_MyClass.myprop-(LPC0_0+4))
LPC0_0:
add r2, pc
ldr r2, [r2]
movs r3, #1
add sp, #8
b.w _objc_getProperty
Ltmp0:
Lfunc_end0:
.cfi_endproc
I want to understand the resulting assembly and have the following questions about it:
1) The last instruction (b.w _objc_getProperty) sets the PC to the address of the label _objc_getProperty. But how does this procedure know where to jump back? Does it assume that the method is invoked with bl, and therefore the link register contains the target address?
2) What do the 3 lines below the second #DEBUG_VALUE do?
If I understand it correctly, the content of r0 is stored at stack offset 4, r1 is stored at the current stack (offset 0), and r0 is filled with stack offset 4. But why does the last instruction changes anything? Doesn't it just mean that r0 is filled with what it already contained? What are the values used for? _obj_getProperty?
3) Why is r3 set to 1 at the end? (movs r3, #1)?
In C code the function would probably look like this:
resulttype Lfunc_begin0(type1 arg1, type2 arg2)
{
return _objc_getProperty(arg1, arg2, Myclass_myprop, 1);
}
First let's look at the following example:
int func(void)
{
a();
b();
return c();
}
It would now be possible to do the function call to "c()" the following way:
save_lr
bl a
bl b
bl c
restore_original_lr
bx lr
Alternatively it would be possible to perform the following code:
save_lr
bl a
bl b
restore_original_lr
b c
In this case the "bx lr" instruction at the end of "c()" will directly jump to the function that called ourself and we do not have to do the "bx lr".
Because some function calls in the C code may destroy the content of R0 and R1 unoptimized C code will save these registers to the stack just for the case that their value is needed later. Well-optimized C code would check this and remove the three instructions after the "#DEBUG" lines. Even the "add SP," and "sub SP," lines could be optimized away!
The _obj_getProperty function obviously takes four arguments. R0 and R1 are simply passed (as shown in the C code above) while R2 and R3 are the additional arguments for that function.
What the 4th argument (R3=1) really means cannot be seen from the assembler code shown here.