News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Calling assembler from C

Started by mats, December 26, 2021, 05:33:07 AM

Previous topic - Next topic

mats

Hi!

I created a simple C program that just passes a pointer to a string to an assembler module where I print it using int 21/function 9. It works fine.


push bp
mov bp,sp
mov dx, word ptr [bp + 4]
mov ah, 9
int 21h


From the same C program I create a 512 byte buffer to read the first sector of a diskette using int 13.


push bp
mov bp, sp

mov bx, word ptr [bp+4]
add bx,16


The read works fine, but when I try to print the content of the sector in my C program, the first 16 bytes are missing in my assembler routine (the pointer points to the address+16 bytes). So in my assembler program I have to add 16 to the pointer that I extract from word ptr[bp+4] in order for it to be correct.

I can not understand why it works with printing the string, where the pointer obviously is correct. While in the second example it is 16 bytes wrong.

This is the contents of the sector using Norton disk editor:


And this is how it looks if I do not adjust the pointer:


My code is in this repository if anyone wants to see.
https://github.com/matspettersson/assemblyplay/tree/main/dos/int13h


Anyone who can explain this behavior to me?

I'm using DOS 3.3, Microsoft C 3.0 and MASM.

Kind regards,
  Mats

mineiro

hello sir mats;
The ($) dollar sign mark end of string to be printed by ms-dos interruption. You can try other interruption to print as an example bios interruption 10h.
Well, I do not have sure if end of string in C is 00h, you need check.

You can try, as example, print "hello", and after that print 08h,08h,08h,08h,08h. The hex 08h is backspace, so, will probably ovewrite previous printed hello and nothing will appear. The hex 09 means tab, hex 0d0ah means new line.
This is the reason why Peter Norton and John Socha in their book assembly to ibm pc printed dots instead of trying to print all chars while developing a hex editor.

If you check output of your program, when you print 0d0ah, this means "enter" key pressed or CRLF. That's the reason of that gap of "blank" lines in showing ascii strings. In norton disk editor shows a symbol, so, they do not used int 21h but probably int 10h from bios.

I can't try that here, sorry. I suggest you create a filter to only print chars from X to Y and if char is not in that range print a dot. The reason is that you can print "control codes" and console/terminal/command prompt will act like moving cursor as an example.

Wait for more suggestions, have grandmasters members here in ms-dos. I wrote without test your program.
I'd rather be this ambulant metamorphosis than to have that old opinion about everything

mats

Hello mineiro!

Thank you for your reply!

The "print string" works fine and I understand that the $ sign is needed for the int 21h. The pointer to the string from the C program is correctly picked up in bp+4 in the assembler function.

But the weird thing is for the other function (_readbootsector). The pointer that is sent in the same way from the same C program is pointing 16 bytes below the actual pointer, so I have to add 16 bytes to it in the assembler function, to get it right when I later in the C program print the contents of the boot sector.

First I thought it had to to with memory models, but I doubt that since all code is in one C file and one ASM file, and since the print method works...

I am sure there is something I have missed. I used to program in assembler in the 80s on my IBM 5155, but that is many years ago. This is just a hobby project to dust off my old skills, so it's really not important. But it made me curious.

Kind regards,
   Mats

mineiro

hello sir mats;
So the problem can be "memory segmentation". Physical addresses are calculated by segment*16+offset, creating a 20 bits final address (real mode). If you have a gap of 16 bytes the reason can be this, segment:offset pairs. I'm supposing that seg:off pair in your program can be 1:0 instead of 0:0.
You can try to move 0 to ds and/or es segment in your asm code. These segments are grouped in your asm code, so point to same address. Maybe it's necessary restore their contents before ret to c code.

;stack frame init
mov ax,0
mov ds,ax
mov es,ax
... int 13h
mov ax,cs/ss
mov ds,ax
mov es,ax
;stack frame end
ret
I'd rather be this ambulant metamorphosis than to have that old opinion about everything

mats

Hello again mineiro!

Many thanks for pointing me in the right direction. This last week I have learned a lot about DOS, 16-bit alignment and segments, and finally my simple program works.

I am blushing when I realize that the problem was in my very short C program, and not in the assembler procedure, where I looked all the time. But it is the journey that is important and I am happy for my learnings.

Happy new year!
    Mats