flat assembler
Message board for the users of flat assembler.
Index
> Linux > converting 32 bit linked fasm to 64 bit g++ inline asm |
Author |
|
fpga 24 Jan 2010, 15:02
I've fallen at the first hurdle and wonder if someone could put me straight
re what I'm doing wrong to get a file descriptor of -14 when I open /dev/vcsa1 Here's my code Code: //My amd64 inline asm version #include <iostream> using namespace std; void my_fn(){ const char * fl = "/dev/vcsa1"; const char * test_str = " "; //make same size as fl int test_int = -1; //ie initialised to fail unless replaced by value //1 open /dev/vcsa1 & return file descriptor in rax __asm__ __volatile__( ".equ sys_open, 2\n" //changed for 64bit ".equ O_RDWR, 02\n" //same for 32 and 64 bit "mov $sys_open, %%rax\n" "mov $O_RDWR, %%rcx\n" "mov $0600, %%rdx\n" //read/write for user in x86. Not sure for AMD64? "syscall\n" //changed from int $0x80 :"=b"(test_str), "=a"(test_int) :"b"(fl) ); //test file name in rbx and returned file descriptor cout << test_str << endl; // /dev/vcsa1 pass cout << test_int << endl; // 2 before syscall -14 after ie fail } int main(){ my_fn(); return 0; } Any help much appreciated EDIT: Here is the fasm code I converted it from konsola.asm (in nasm) found at http://rudy.mif.pg.gda.pl/~bogdro/linux/tryb_txt_linux_en.html Hope this helps Code: ;format ELF executable ;commented out and replaced with... format ELF64 ;entry start ;commented out and replaced with... public _print_str as 'print_str' sys_exit equ 1 sys_read equ 3 sys_write equ 4 sys_open equ 5 sys_close equ 6 sys_lseek equ 19 SEEK_SET equ 0 O_RDWR equ 02o ; position to display nasz_wiersz equ 10 nasza_kolumna equ 10 ;start: ;commented out and replaced with... _print_str: mov eax, sys_open ; open the file mov ebx, plik ; file name mov ecx, O_RDWR ; read and write mov edx, 600o ; read and write for the user int 80h ; open cmp eax, 0 jl .koniec mov ebx, eax ; file handle mov eax, sys_read ; read the file (console attributes first) mov ecx, konsola ; where to read mov edx, 4 ; how many bytes to read int 80h mov eax, sys_lseek ; seek to the correct psition movzx ecx, byte [l_kolumn] ; zero extends dest operand to size of source operand imul ecx, nasz_wiersz add ecx, nasza_kolumna ; ECX=row*row length + column shl ecx, 1 ; ECX *= 2, because there are 2 bytes ; on the screen for each character: ; the character and its attribute add ecx, 4 ; +4, because we're moving from ; the beginning of the file mov edx, SEEK_SET ; start at the beginning of the file int 80h mov eax, sys_write ; writing to the file mov ecx, znak ; what to write mov edx, 2 ; how many bytes to write int 80h mov eax, sys_close ; close the file int 80h xor eax, eax ; EAX = 0 = no errors .koniec: mov ebx, eax mov eax, sys_exit int 80h ; exit with zero code or the error, ; from opening the file plik db "/dev/vcsa1", 0 ; first text console file ; attributes of the console: konsola: l_wierszy db 0 l_kolumn db 0 kursor_x db 0 kursor_y db 0 ; character with the attribute we're going to display: znak db "*" ;<<<<<<HERE atrybut db 43h ; skyblue on red ;<<<<<<HERE Code: /* this file is a .cpp skeleton just to link object file of fasm konsola.asm */ using namespace std; extern "C" void print_str(); int main(){ print_str(); return 0; } Just linked the two like this Code: #!/bin/sh #create the exe "linked_konsola" ./fasm linked_konsola_fasm.asm linked_konsola_fasm.o g++ -c linked_konsola_cpp.cpp g++ -o linked_konsola linked_konsola_fasm.o linked_konsola_cpp.o To run it I did... ctrl/alt/F1 su'd to get root permissions ./linked_konsola It prints a red start on a blue background at postion 10,10 Last edited by fpga on 24 Jan 2010, 15:49; edited 5 times in total |
|||
24 Jan 2010, 15:02 |
|
revolution 24 Jan 2010, 15:26
Erm, where is the fasm code?
|
|||
24 Jan 2010, 15:26 |
|
fpga 24 Jan 2010, 15:36
I've included it in the 1st post now. Hope it helps.
|
|||
24 Jan 2010, 15:36 |
|
fpga 24 Jan 2010, 17:24
Good question!
Yes there is. This code is for updating the screen for a text based simulation and many processed parts/characters will need to be redrawn as a result of their state/position being changed during each screen update. The parts' char, x, y and fg/bg colour attribute are embedded in nested c++ objects and the different types of the outer objects are stored in various stl vectors. As such I need to loop through such vectors and interrogate their nested objects for the display information. I don't fancy looping through these structures in asm unless there's an easy way and don't want to incur the cost of a call to asm for each part that needs redisplaying. ie Code: void Update_screen(){ for each machine in vector for each part in machine asm bit ( suck part.char into reg a suck part.fg_bg into reg b etc write char directly to video ram without call overhead } I hope this explains why Edit: Just seen your further post Thank you for your advice I did a .S of an example c "open file" program which used the relevant include files. It looked a nightmare and I hadn't got a clue what some of the routines were that were being called. I would have thought the routines were corruption but for the word "call" preceding them. |
|||
24 Jan 2010, 17:24 |
|
f0dder 25 Jan 2010, 00:41
fpga wrote: As such I need to loop through such vectors and interrogate their nested objects for the display information. I don't fancy looping through these structures in asm unless there's an easy way and don't want to incur the cost of a call to asm for each part that needs redisplaying. Instead of focusing on optimizing CALL overhead away, though, you should focus on optimizing the routine - calling a write per char is pretty bad, the CALL overhead you're optimizing away is going to be neglicible compared to the user->kernel->user overhead, and the various processing done as well. Unfortunately, afiak mmap()'ing a /dev/vcs* file doesn't work (at least I couldn't get it to work), that would have been a nice way of accessing the textmode buffer. I suggest you keep your own copy of the textmode memory though, do your drawing directly to this buffer, and when you need a redisplay simply write this entire buffer to the /dev/vcs* file handle you have open - no need to bother about doing direct SYSCALLs then, CALL overhead to write() won't be a problem. If you're frequently only doing very small updates, you can employ partial-refresh optimizations... I suppose an "isDirty" flag per line is enough, doing it for each individual cell is too much overhead (counting both storage for detection, code time for doing detection, and the call overhead for display individual characters). Also, have you considered looking at ncurses? Manually writing to a vcs is faster, but afaik ncurses isn't that bad... and it's more portable (vcs doesn't even work across SSH) and has a lot of pre-baked functionality (including partial screen refreshes, afaik). fpga wrote: I did a .S of an example c "open file" program which used the relevant include files. |
|||
25 Jan 2010, 00:41 |
|
fpga 25 Jan 2010, 10:08
Code: //My amd64 inline asm version //this now returns a file descriptor of 3 #include <iostream> using namespace std; void my_fn(){ const char * fl = "/dev/vcsa1"; const char * test_str = " "; //make same size as fl int test_int = -1; //fails unless replaced by value unsigned char buf[] = {0,0,0,0}; //1 open /dev/vcsa1 & return file descriptor in rax __asm__ __volatile__( ".equ sys_open,2\n" ".equ O_RDWR,02\n" "movq $sys_open,%%rax\n" "movq $O_RDWR,%%rsi\n" "movq $0600,%%rdx\n" //read/write for user in x86. Not sure for AMD64? "syscall\n" :"=D"(test_str),"=a"(test_int) :"D"(fl) //rdi :"rsi","rdx","rcx","r10","r11","cc" //Is this enough ); //cout << test_str << endl; // /dev/vcsa1 ie pass //cout << test_int << endl; // 3 ie pass //read 1st 4 bytes of file into buf[] __asm__ __volatile__( "movq %%rax, %%rsi\n" //returned file descriptor into rsi "movq $0,%%rax\n" //syscall read into rax "movq $4,%%rdx\n" //qty of bytes to read into rdx "syscall\n" :"=a"(test_int) :"D"(&buf[0]) //ptr of where to place 1st byte into rdi :"rsi","rdx","rcx","r10","r11","cc" ); cout << test_int << endl; //returning -9 expected 4 ie fail } int main(){ my_fn(); return 0; } I appear to have made some progress in that I'm now getting 3 as a file descriptor when I (seem to) open /dev/vcsa1. The problem was that in addition to changing the equates, 64bit Linux seems to use different registers too. I'm now struggling with the read statement which is telling me I'm reading -9 bytes instead of the 4 specified. I completely agree with your advice that one write per char is unreasonable and that dirty lines + a single write per screen update is the way to go. My current display system is in ncurses. It works but disappointingly compared to my powerbasic version. I wrote the graphics module on that using the windows api. It was more akin to your above suggestion ie updating a data structure and then blitting the whole lot to the screen. This is not a criticism of ncurses 'cos it's a UI not a fast graphics library. I'll look into doing things the way that you suggest and thank you very much for your advice. Perhaps the above thread ie http://board.flatassembler.net/topic.php?t=5950 will throw some light on where I'm going wrong perhaps not ie "and plans for a near future: - make 64bit version. (most likely will go into separate package. not sure yet.)" Thx for the thread anyway arafel |
|||
25 Jan 2010, 10:08 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.