VOGONS


AMD64/x86_64 Solution

Topic actions

First post, by cyfin

User metadata
Rank Newbie
Rank
Newbie

I was having trouble running DOSBox 0.61 on my GNU Linux x86_64 ( custom built distribution). I did some gdb-ing and found it was SEG Faulting in /src/gui/render_templates.h line 13: "case 32:*(Bit32u*)dst=val;dst+=4;break;"

Problem is Bit32u is not 32 bits. Therefore adding 4 is wrong. (maybe adding by sizeof(Bit32u) would be better/safer?)

In include/dosbox.h you define bit32u as "typedef unsigned long Bit32u;"

On a 64 bit system, unsinged long is 64 bits. to fix this, I used

#include <stdint.h>

typedef uint8_t Bit8u;
typedef int8_t Bit8s;
typedef uint16_t Bit16u;
typedef int16_t Bit16s;
typedef uint32_t Bit32u;
typedef int32_t Bit32s;

I'm no expert, but this got it all working fine for me. I'm not sure about its portability though. Hope this helps

Reply 2 of 23, by cyfin

User metadata
Rank Newbie
Rank
Newbie

It was SEG Faulting with the typical SDL parachute thing. Windows XP would not be affected by this problem because windows does not use 64 bit. This only would occur with Linux compiling as 64 bit. As for the performance, I did not notice any kinds of slow down. But I have not played with it for a long duration yet

Reply 3 of 23, by Qbix

User metadata
Rank DOSBox Author
Rank
DOSBox Author

you might want to check this archive ( if you want)

http://pcnwstage.phys.rug.nl/dosboxcvs.tgz

it contains the cvs source. There is some size detection in there.
Could you test if that works under x64 mode ?

Water flows down the stream
How to ask questions the smart way!

Reply 4 of 23, by cyfin

User metadata
Rank Newbie
Rank
Newbie

That CVS compiled and ran fine. There were a lot of compiler warnings, but no errors.

Attachments

  • Filename
    output.txt
    File size
    75.66 KiB
    Downloads
    184 downloads
    File comment
    Make output
    File license
    Fair use/fair dealing exception
  • Filename
    config.h
    File size
    6.05 KiB
    Downloads
    169 downloads
    File license
    Fair use/fair dealing exception

Reply 6 of 23, by jal

User metadata
Rank Oldbie
Rank
Oldbie
cyfin wrote:

"case 32:*(Bit32u*)dst=val;dst+=4;break;"

Problem is Bit32u is not 32 bits. Therefore adding 4 is wrong. (maybe adding by sizeof(Bit32u) would be better/safer?)

You could of course let the compiler do that for you, and write

((Bit32u *)dst)++;
cyfin wrote:

On a 64 bit system, unsinged long is 64 bits. to fix this, I used

Are you sure that is portable? A while back, I read 64 bit Unices took a different approach than Windows. I believe Windows had int = 64, long = 32, whereas the Unices used int = 64, long = 64.

JAL

Reply 7 of 23, by cyfin

User metadata
Rank Newbie
Rank
Newbie

int == 64 and long == 32 on windows? That doesnt sound right. Why would a int be larger than a long int? Windows API calles for Double words instead of long. I've have not seen windows 64 bit version yet. Do they change the API to something else ( DOUBLE DOUBLE WORD? ) or do they just call a 64 bit a DOUBLE WORD? However, what I have gathered from unicies is that there is no set size for any value. A char does not have to be 8 bits, it just happens to be on most systems. Therefore, you can never rely on the size. I find it works just to use uint64_t. If I'm not mistaken, windows uses that convention as well. I dont think its in the C/C++ standard though.

I didnt think about ((Bit32u *)dst)++; before. I tested it and it works fine. I'll remember that one in the future;

Reply 8 of 23, by jal

User metadata
Rank Oldbie
Rank
Oldbie
cyfin wrote:

int == 64 and long == 32 on windows? That doesnt sound right. Why would a int be larger than a long int?

That doesn't sound right indeed. My memory got me confused 😀. One of the articles I read around the first time 64-bits got interesting was

http://www.microsoft.com/msj/0798/hood0798.aspx

Win64 has both ints and longs as 32 bit, and pointers as 64 bit.

cyfin wrote:

use uint64_t. If I'm not mistaken, windows uses that convention as well.

Visual C++ uses __int64, Win32 uses nasty structs in its APIs.

cyfin wrote:

I didnt think about ((Bit32u *)dst)++; before. I tested it and it works fine. I'll remember that one in the future;

It's quite a neat trick, that not many C(++)-programmers seem to know: when using the ++ operator, the compiler checks the datatype of the pointer that's ++ed and adds the sizeof() of that datatype to the pointer. It also works fine with pointers to structs or classes, for example. It stems from the basic rule that in C(++), a[1] is equal to *(a+1), so that a pointer addition is on the same level as array indexation.

JAL

Reply 9 of 23, by cyfin

User metadata
Rank Newbie
Rank
Newbie

Intresting article. I'm not much a fan of Windows ( and its API ) and therefore don't care much, but It looks like Windows API is going to be really really screwed up when it comes to 64-Bit. I think they should go back to 2-bits and work their way up from there.

Looking at the msdn libary and __int64, I found it strange that there is no unsinged version. Is it possible to declare an "unsigned __int64"?

Reply 10 of 23, by `Moe`

User metadata
Rank Oldbie
Rank
Oldbie

fmopl.c and ymf262.c warnings are normal. They didn't write that code.
Not sure about the others.

This one is dangerous, and typical for a non-64bit-clean application:

drive_cache.cpp:306: warning: cast from pointer to integer of different size

It may not be noticeable, everything working fine millions of times, and then, all of a sudden, mysterious failures/crashes appear. It's not urgent as long as it works, but should be fixed.

Reply 11 of 23, by Qbix

User metadata
Rank DOSBox Author
Rank
DOSBox Author
int DOS_Drive_Cache::CompareShortname(const char* compareName, const char* shortName)
{
char* cpos = strchr(shortName,'~');
if (cpos) {
Bits compareCount1 = (int)cpos - (int)shortName;
char* endPos = strchr(cpos,'.');
Bitu numberSize = endPos ? int(endPos)-int(cpos) : strlen(cpos);

char* lpos = strchr(compareName,'.');
Bits compareCount2 = lpos ? int(lpos)-int(compareName) : strlen(compareName);
if (compareCount2>8) compareCount2 = 8;

compareCount2 -= numberSize;
if (compareCount2>compareCount1) compareCount1 = compareCount2;
return strncmp(compareName,shortName,compareCount1);
}
return strcmp(compareName,shortName);
};

the line 306 is :

                Bits compareCount1      = (int)cpos - (int)shortName;

I'm posting the whole fragment as comparable casts are used in this fragment a lot. Feel free to create a 64 bit warning free code.

Water flows down the stream
How to ask questions the smart way!

Reply 12 of 23, by `Moe`

User metadata
Rank Oldbie
Rank
Oldbie

Is there a compelling reason not to use:

Bits compareCount1      = (int)(cpos - shortName);

? Pointer arithmetics on char* pointers is perfectly valid and does the right thing.

Reply 13 of 23, by jal

User metadata
Rank Oldbie
Rank
Oldbie
cyfin wrote:

Looking at the msdn libary and __int64, I found it strange that there is no unsinged version. Is it possible to declare an "unsigned __int64"?

Yes, it is. To display __int64s with stdio, "%I64" is used as a prefix, like

printf ("signed: %I64d, unsigned: %I64u", val1, val2);

No doubt this isn't portable either...

JAL

Reply 14 of 23, by cyfin

User metadata
Rank Newbie
Rank
Newbie
Bits compareCount1      = (int)cpos - (int)shortName; 

Only Works if the high bits that get truncated from the type cast are the same.

Bits compareCount1      = (int)(cpos - shortName);

This is a better solution, but not the best. If the size difference of the two pointers is greater than the size of an int, then you will have problems.

Looking though the string functions, I'd probably use

Bits compareCount1 = strcspn(shortname, "~");
if( compareCount1 < strlen(shortname) )
{
...
}

Just a thought: This code requires that the memory addresses be allocated from low values to high values ( cpos-shortname). If I remember my assemby class, I think there were some architectures that do it from High to Low (shortname-cpos). Is that right? Or do all systems go from low to high?

Reply 15 of 23, by jal

User metadata
Rank Oldbie
Rank
Oldbie
cyfin wrote:

Just a thought: This code requires that the memory addresses be allocated from low values to high values ( cpos-shortname). If I remember my assemby class, I think there were some architectures that do it from High to Low (shortname-cpos). Is that right? Or do all systems go from low to high?

You are no doubt thinking about little/big-endianess. However, that does not play a role when using strings. Strings are not architecture-dependant: the cpu does not 'know' strings. The endianess (i.e. the orientation of bytes within a word) only comes into play when using integers (16/32/64 bits).

JAL

Reply 16 of 23, by cyfin

User metadata
Rank Newbie
Rank
Newbie

I'm refering to Memory Addressing. If I allocate a 5 byte block on my computer, i get a pointer to 001. And the machine allocates:
001 <- pointer here.
002
003
004
005

I thought there were some systems that work the other way:

005 <- pointer here
004
003
002
001

so pointer[4] would return 001

Then again, i'm probably dreaming this whole thing up 😜

Reply 17 of 23, by `Moe`

User metadata
Rank Oldbie
Rank
Oldbie

Just to keep some fire to this discussion, and to annoy developers in general ( 😀 ), here's something I read in WINE's header files today:

Win32 was easy to implement under Unix since most (all?) 32-bit Unices uses the same type model (ILP32) as Win32, where int, long and pointer are 32-bit.

Win64, however, will cause some problems when implemented under Unix. Linux/{Alpha, Sparc64} and most (all?) other 64-bit Unices uses the LP64 type model where int is 32-bit and long and pointer are 64-bit. Win64 on the other hand uses the P64 (sometimes called LLP64) type model where int and long are 32 bit and pointer is 64-bit.

Seems like there will even be a difference between x86_64/Windows and x86_64/Linux. Sounds like a _lot_ of fun. Luckily, DosBox already provides explicitly sized types (Bitu32, ...), so while anyone working on it should be aware of the (IMHO insane) type size differences, there's at least some hope. BTW, I even recall hearing of some system where int=64bit and long=32bit.

Reply 18 of 23, by Qbix

User metadata
Rank DOSBox Author
Rank
DOSBox Author

fixed it using the folowing patch.

Index: drive_cache.cpp
===================================================================
RCS file: /cvsroot/dosbox/dosbox/src/dos/drive_cache.cpp,v
retrieving revision 1.40
diff -u -r1.40 drive_cache.cpp
--- drive_cache.cpp 13 Nov 2004 12:08:43 -0000 1.40
+++ drive_cache.cpp 15 Dec 2004 20:03:06 -0000
@@ -317,7 +317,8 @@
{
char* cpos = strchr(shortName,'~');
if (cpos) {
- Bits compareCount1 = (int)cpos - (int)shortName;
+/* the following code is replaced as it's not safe when char* is 64 bits */
+/* Bits compareCount1 = (int)cpos - (int)shortName;
char* endPos = strchr(cpos,'.');
Bitu numberSize = endPos ? int(endPos)-int(cpos) : strlen(cpos);

@@ -327,6 +328,18 @@

compareCount2 -= numberSize;
if (compareCount2>compareCount1) compareCount1 = compareCount2;
+*/
+ size_t compareCount1 = strcspn(shortName,"~");
+ size_t numberSize = strcspn(cpos,".");
+ size_t compareCount2 = strcspn(compareName,".");
+ if(compareCount2 > 8) compareCount2 = 8;
+ /* We want
+ * compareCount2 -= numberSize;
+ * if (compareCount2>compareCount1) compareCount1 = compareCount2;
+ * but to prevent negative numbers:
+ */
+ if(compareCount2 > compareCount1 + numberSize)
+ compareCount1 = compareCount2 - numberSize;
return strncmp(compareName,shortName,compareCount1);
}
return strcmp(compareName,shortName);

Water flows down the stream
How to ask questions the smart way!