Latest Tweets

DASM 2.20.11 on Linux fires a Segfault whenever assembling 6205/6207 code.

The issue

When I was a child, some time ago, I used to play video games in my amazingly – at that time-  Atari 2600 VCS. Having now some time to spare, I have decided to learn how to develop games on this old-fashioned platform. In order to do so, the first step is to learn its assembly language, being the one for the 6205/6207 processors. The DASM assembler is the one recommended to generate binary code for this platform, among other things because it does include support development files for the Atari 2600 VCS itself. Besides, it is pretty obvious that it can generate 6205/6207 object code.

Therefore, I downloaded its sources and compiled it on my Debian Wheezy, in order to start the learning process. Before actually reading how to develop code for the Atari 2600 VCS, I tried to assemble a demo sample code – included with DASM – to make sure I had everything well set up on my computer. However, whenever assembling this demo code, I got a Segmentation Fault as clearly shown below:

../../bin/dasm boing26.asm -f3 -I../../machines/atari2600/ -oboing26.bin
make[2]: *** [boing26.bin] Segmentation fault

Once again, it’s time for debugging! 😉

 I recompiled the DASM source code adding the -g flag, so that I could get its debugging symbols inside a GDB session. Then, I re-ran the assembler inside GDB and I got this:

Program received signal SIGSEGV, Segmentation fault.
clearsegs () at main.c:842
842 seg->flags = (seg->flags & SF_BSS) | SF_UNKNOWN;

Therefore, the segmentation fault was fired inside the clearsegs() function, exactly in line number 842. Normally, the problem could be right before entering a particular function due to an erroneous argument. However, this was not the case because, as clearly seen in the definition of clearsegs() function, it had no arguments at all:

(gdb) list
837 void clearsegs(void)
838 {
839 SEGMENT *seg;
840
841 for (seg = Seglist; seg; seg = seg->next) {
842 seg->flags = (seg->flags & SF_BSS) | SF_UNKNOWN;
843 seg->rflags= seg->initflags = seg->initrflags = SF_UNKNOWN;
844 }
845 }

The problem had to be located inside clearsegs(), then. Having a quick look at the problematic line, it was quite obvious that the pointer seg was, in fact, a reference to a linked list structure. Trying to access the next element fired the segmentation fault. Well, it seemed quite easy to fix. There was just one SEGMENT in the Seglist linked list structure. To find out this, I used the GDB this way:

(gdb) b main.c:842
Breakpoint 1 at 0x401569: file main.c, line 842.
(gdb) p seg->name
$2 = 0x424070 “INITIAL CODE SEGMENT”
(gdb) p seg->next
Cannot access memory at address 0x2f

Conclusion: somewhere inside the DASM source code, the Seglist was not actually setting its last node to NULL. Easy as pie!

Using cscope to look for the initialization of the Seglist linked list

 After running the cscope utility inside the DASM source code directory this way:

~$ cscope -R

and looking for the literal “INITIAL CODE SEGMENT”, I found out that there was a #define called ISEGNAME. Then, I looked for this symbol inside the sources using cscope once again and this is what came out:

C symbol: ISEGNAME

File Function Line
0 main.c <global> 41 #define ISEGNAME “INITIAL CODE SEGMENT”
1 main.c MainShadow 523 seg->name = strcpy(permalloc(sizeof(ISEGNAME)), ISEGNAME);

Clearly enough, the problem seemed to be located in the MainShadow() function. Editing the main.c file I got this:

521 {
522 SEGMENT *seg = (SEGMENT *)permalloc(sizeof(SEGMENT));
523 seg->name = strcpy(permalloc(sizeof(ISEGNAME)), ISEGNAME);
524 seg->flags= seg->rflags = seg->initflags = seg->initrflags = SF_UNKNOWN;
525 Csegment = Seglist = seg;
526 }

Okay so … where’s the last element in this linked list? It is nowhere to be seen! DASM developers made an awful and simple mistake that impeded the assembler from actually working! I had to fix this by adding just a trivial line of code BEFORE actually setting Csegment, Seglist and seg the same liked list. So, this code snippet would be altered this way:

521 {
522 SEGMENT *seg = (SEGMENT *)permalloc(sizeof(SEGMENT));
523 seg->name = strcpy(permalloc(sizeof(ISEGNAME)), ISEGNAME);
524 seg->flags= seg->rflags = seg->initflags = seg->initrflags = SF_UNKNOWN;
525 /* TCG patch, the next node must be NULL */
526 seg->next = NULL;
527 Csegment = Seglist = seg;
528 }

Assembling the demo sample and running it

Now, I re-ran the assembler and I could get the object code with no errors:

(gdb) r
Starting program: /home/tonicas/dev/atari2600/soft/dasm-2.20.11/bin/dasm boing26.asm -f3 -I../../machines/atari2600/ -oboing26.bin
[Inferior 1 (process 17383) exited normally]

Finally, I ran the resulting object code inside the Stella emulator, just to be sure it was working fine. It was! See the screenshot below:

The demo Atari 2600 code included with DASM, after being assembled and running inside the Stella emulator

The demo Atari 2600 code included with DASM, after being assembled and running inside the Stella emulator

Now, I am gonna start reading all about Atari 2600 VCS development, in order to create some cool video game!!!! 🙂 Life is good sometimes, don’t you think? Get the patched DASM version FROM HERE.