Adding external assembler function to C project - c
I'm trying to call assembler procedure which is supposed to calculate CRC32 checksum for file from C app.
C code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
extern unsigned long __stdcall CRC32(size_t sizeOfFile, char buffer[]);
int fsize(char* file) {
int size;
FILE* fh;
fopen_s(&fh, file, "rb" );
if(fh != NULL){
if( fseek(fh, 0, SEEK_END) ){
fclose(fh);
return -1;
}
size = ftell(fh);
fclose(fh);
return size;
}
return -1; //error
}
void calculateChecksum(char * filename, char * checksum){
FILE *file = NULL;
unsigned long crc32;
char hex[10];
fopen_s(&file, filename, "rb" );
size_t size = fsize(filename);
char *buffer=(char*)malloc(size);
fread_s(buffer,size,size,1,file);
crc32=CRC32(size,buffer);
int n = sprintf_s(hex,"%x",crc32);
for (int i=0;i<8;i++){
checksum[i]=hex[i];
}
fclose(file);
file = NULL;
}
int main(){
char checksum[8];
calculateChecksum("B:\\secretMessageC#.txt",checksum);
char hex[10];
for (int i=0;i<8;i++){
checksum[i]=hex[i];
printf("%c",checksum[i]);
}
getchar();
return 0;
}
Assember code:
.686
.387
.model flat, stdcall
.xmm
.data
.code
CRC32 proc sizeOfFile:DWORD, file:DWORD
push esi
push ecx
push edx
mov esi, file
xor edx, edx
or eax, -1
mov ecx, sizeOfFile
CRC32_loop:
mov dl, byte ptr [esi]
xor dl, al
shr eax, 8
xor eax, dword ptr [crc32_table + 4*edx]
inc esi
dec ecx
jnz CRC32_loop
not eax
pop edx
pop ecx
pop esi
ret
CRC32 endp
crc32_table dd 000000000h, 077073096h, 0EE0E612Ch, 0990951BAh, 0076DC419h, 0706AF48Fh, 0E963A535h, 09E6495A3h, 00EDB8832h, 079DCB8A4h
dd 0E0D5E91Eh, 097D2D988h, 009B64C2Bh, 07EB17CBDh, 0E7B82D07h, 090BF1D91h, 01DB71064h, 06AB020F2h, 0F3B97148h, 084BE41DEh
dd 01ADAD47Dh, 06DDDE4EBh, 0F4D4B551h, 083D385C7h, 0136C9856h, 0646BA8C0h, 0FD62F97Ah, 08A65C9ECh, 014015C4Fh, 063066CD9h
dd 0FA0F3D63h, 08D080DF5h, 03B6E20C8h, 04C69105Eh, 0D56041E4h, 0A2677172h, 03C03E4D1h, 04B04D447h, 0D20D85FDh, 0A50AB56Bh
dd 035B5A8FAh, 042B2986Ch, 0DBBBC9D6h, 0ACBCF940h, 032D86CE3h, 045DF5C75h, 0DCD60DCFh, 0ABD13D59h, 026D930ACh, 051DE003Ah
dd 0C8D75180h, 0BFD06116h, 021B4F4B5h, 056B3C423h, 0CFBA9599h, 0B8BDA50Fh, 02802B89Eh, 05F058808h, 0C60CD9B2h, 0B10BE924h
dd 02F6F7C87h, 058684C11h, 0C1611DABh, 0B6662D3Dh, 076DC4190h, 001DB7106h, 098D220BCh, 0EFD5102Ah, 071B18589h, 006B6B51Fh
dd 09FBFE4A5h, 0E8B8D433h, 07807C9A2h, 00F00F934h, 09609A88Eh, 0E10E9818h, 07F6A0DBBh, 0086D3D2Dh, 091646C97h, 0E6635C01h
dd 06B6B51F4h, 01C6C6162h, 0856530D8h, 0F262004Eh, 06C0695EDh, 01B01A57Bh, 08208F4C1h, 0F50FC457h, 065B0D9C6h, 012B7E950h
dd 08BBEB8EAh, 0FCB9887Ch, 062DD1DDFh, 015DA2D49h, 08CD37CF3h, 0FBD44C65h, 04DB26158h, 03AB551CEh, 0A3BC0074h, 0D4BB30E2h
dd 04ADFA541h, 03DD895D7h, 0A4D1C46Dh, 0D3D6F4FBh, 04369E96Ah, 0346ED9FCh, 0AD678846h, 0DA60B8D0h, 044042D73h, 033031DE5h
dd 0AA0A4C5Fh, 0DD0D7CC9h, 05005713Ch, 0270241AAh, 0BE0B1010h, 0C90C2086h, 05768B525h, 0206F85B3h, 0B966D409h, 0CE61E49Fh
dd 05EDEF90Eh, 029D9C998h, 0B0D09822h, 0C7D7A8B4h, 059B33D17h, 02EB40D81h, 0B7BD5C3Bh, 0C0BA6CADh, 0EDB88320h, 09ABFB3B6h
dd 003B6E20Ch, 074B1D29Ah, 0EAD54739h, 09DD277AFh, 004DB2615h, 073DC1683h, 0E3630B12h, 094643B84h, 00D6D6A3Eh, 07A6A5AA8h
dd 0E40ECF0Bh, 09309FF9Dh, 00A00AE27h, 07D079EB1h, 0F00F9344h, 08708A3D2h, 01E01F268h, 06906C2FEh, 0F762575Dh, 0806567CBh
dd 0196C3671h, 06E6B06E7h, 0FED41B76h, 089D32BE0h, 010DA7A5Ah, 067DD4ACCh, 0F9B9DF6Fh, 08EBEEFF9h, 017B7BE43h, 060B08ED5h
dd 0D6D6A3E8h, 0A1D1937Eh, 038D8C2C4h, 04FDFF252h, 0D1BB67F1h, 0A6BC5767h, 03FB506DDh, 048B2364Bh, 0D80D2BDAh, 0AF0A1B4Ch
dd 036034AF6h, 041047A60h, 0DF60EFC3h, 0A867DF55h, 0316E8EEFh, 04669BE79h, 0CB61B38Ch, 0BC66831Ah, 0256FD2A0h, 05268E236h
dd 0CC0C7795h, 0BB0B4703h, 0220216B9h, 05505262Fh, 0C5BA3BBEh, 0B2BD0B28h, 02BB45A92h, 05CB36A04h, 0C2D7FFA7h, 0B5D0CF31h
dd 02CD99E8Bh, 05BDEAE1Dh, 09B64C2B0h, 0EC63F226h, 0756AA39Ch, 0026D930Ah, 09C0906A9h, 0EB0E363Fh, 072076785h, 005005713h
dd 095BF4A82h, 0E2B87A14h, 07BB12BAEh, 00CB61B38h, 092D28E9Bh, 0E5D5BE0Dh, 07CDCEFB7h, 00BDBDF21h, 086D3D2D4h, 0F1D4E242h
dd 068DDB3F8h, 01FDA836Eh, 081BE16CDh, 0F6B9265Bh, 06FB077E1h, 018B74777h, 088085AE6h, 0FF0F6A70h, 066063BCAh, 011010B5Ch
dd 08F659EFFh, 0F862AE69h, 0616BFFD3h, 0166CCF45h, 0A00AE278h, 0D70DD2EEh, 04E048354h, 03903B3C2h, 0A7672661h, 0D06016F7h
dd 04969474Dh, 03E6E77DBh, 0AED16A4Ah, 0D9D65ADCh, 040DF0B66h, 037D83BF0h, 0A9BCAE53h, 0DEBB9EC5h, 047B2CF7Fh, 030B5FFE9h
dd 0BDBDF21Ch, 0CABAC28Ah, 053B39330h, 024B4A3A6h, 0BAD03605h, 0CDD70693h, 054DE5729h, 023D967BFh, 0B3667A2Eh, 0C4614AB8h
dd 05D681B02h, 02A6F2B94h, 0B40BBE37h, 0C30C8EA1h, 05A05DF1Bh, 02D02EF8Dh
end
While bulding, I'm getting those three errors:
1>------ Build started: Project: ConsoleApplication5, Configuration: Debug Win32 ------
1> Assembling C:\Users\sliwkacz\Desktop\New folder\crc32.asm...
1>C:\Users\sliwkacz\Desktop\New folder\crc32.asm(7): error A2206: missing operator in expression
1>C:\Users\sliwkacz\Desktop\New folder\crc32.asm(12): error A2006: undefined symbol : file
1>C:\Users\sliwkacz\Desktop\New folder\crc32.asm(15): error A2081: missing operand after unary operator
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\BuildCustomizations\masm.targets(49,5): error MSB3721: The command "ml.exe /c /nologo /Zi /Fo"Debug\crc32.obj" /W3 /errorReport:prompt /Ta"C:\Users\sliwkacz\Desktop\New folder\crc32.asm"" exited with code 1.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
I'll be very greatful for any hint that can helps.
size is a reserved word in MASM assembly, so you'll have to come up with a different name for your parameter.
You're also missing a CRC32 ENDP after the ret.
And you might have to change the function declaration in your C file to extern unsigned long __stdcall CRC32(size_t *bufLen, FILE *file);
By the looks of it, your CRC32 function is using its arguments in an incorrect manner. The size argument is a pointer to the size, but you're using it as if it was the size itself. And it seems like you try to read from a FILE* as if was a pointer to the data in the file, but I'm pretty sure a FILE* is just a pointer to a struct containing information about an opened file. To access the data in the file you should use fread to read chunks of data into a buffer.
Related
INT 13 Extension Read in C
i can use extended read functions of bios int 13h well from assembly, with the below code ; ************************************************************************* ; Setup DISK ADDRESS PACKET ; ************************************************************************* jmp strtRead DAPACK : db 010h ; Packet Size db 0 ; Always 0 blkcnt: dw 1 ; Sectors Count db_add : dw 07e00h ; Transfer Offset dw 0 ; Transfer Segment d_lba : dd 1 ; Starting LBA(0 - n) dd 0 ; Bios 48 bit LBA ; ************************************************************************* ; Start Reading Sectors using INT13 Func 42 ; ************************************************************************* strtRead: mov si, OFFSET DAPACK; Load DPACK offset to SI mov ah, 042h ; Function 42h mov dl, 080h ; Drive ID int 013h; Call INT13h i want to convert this to be a c callable function but i have no idea about how to transfer the parameters from c to asm like drive id , sectors count, buffer segment:offset .... etc. i am using msvc and masm and working with nothing except bios functions. can anyone help ?!! update : i have tried the below function but always nothing loaded into the buffer ?? void read_sector() { static unsigned char currentMBR[512] = { 0 }; struct disk_packet //needed for int13 42h { byte size_pack; //size of packet must be 16 or 16+ byte reserved1; //reserved byte no_of_blocks; //nof blocks for transfer byte reserved2; //reserved word offset; //offset address word segment; //segment address dword lba1; dword lba2; } disk_pack; disk_pack.size_pack = 16; //set size to 16 disk_pack.no_of_blocks = 1; //1 block ie read one sector disk_pack.reserved1 = 0; //reserved word disk_pack.reserved2 = 0; //reserved word disk_pack.segment = 0; //segment of buffer disk_pack.offset = (word)¤tMBR[0]; //offset of buffer disk_pack.lba1 = 0; //lba first 32 bits disk_pack.lba2 = 0; //last 32 bit address _asm { mov dl, 080h; mov[disk_pack.segment], ds; mov si, disk_pack; mov ah, 42h; int 13h ; jc NoError; //No error, ignore error code ; mov bError, ah; // Error, get the error code NoError: } }
Sorry to post this as "answer"; I want to post this as "comment" but it is too long... Different compilers have a different syntax of inline assembly. This means that the correct syntax of the following lines: mov[disk_pack.segment], ds; mov si, disk_pack; ... depends on the compiler used. Unfortunately I do not use 16-bit C compilers so I cannot help you in this point. The next thing I see in your program is the following one: disk_pack.segment = 0; //segment of buffer disk_pack.offset = (word)¤tMBR[0]; //offset of buffer With a 99% chance this will lead to a problem. Instead I would to the following: struct disk_packet //needed for int13 42h { byte size_pack; byte reserved; word no_of_blocks; // note that this is 16-bit! void far *data; // <- This line is the main change! dword lba1; dword lba2; } disk_pack; ... disk_pack.size_pack = 16; disk_pack.no_of_blocks = 1; disk_pack.reserved = 0; disk_pack.data = ¤tMBR[0]; // also note the change here disk_pack.lba1 = 0; disk_pack.lba2 = 0; ... Note that some compilers name the keyword "_far" or "__far" instead of "far". A third problem is that some (buggy) BIOSes require ES to be equal to the segment value from the disk_pack and a fourth one is that many compilers require the inline assembly code not to modify any registers (AX, CX and DX is normally OK). These two could be solved the following way: push ds; push es; push si; mov dl, 080h; // TODO here: Set ds:si to disk_pack in a compiler-specific way mov es,[si+6]; mov ah, 42h; int 13h; ... pop si; pop es; pop ds; In my opinion the "#pragma pack" should not be neccessary because all elements in the structure are propperly aligned.
Assembly, draw an image
I need to draw QRCode via Assembly(intel)+C(c99) in DOS. But it seems I have too little memory for it. I tried to store image as bit array: image db 11111110b, ... But anyway I had no result(Illegal read from 9f208c70, CS:IP 192:9f20734f). Now I don't know what to do. Here is code I used: module.asm: [bits 16] global setpixel global setVM global getch global getPixelBlock section .text setVM: push bp mov bp, sp mov ax, [bp+6] mov ah, 0 int 10h pop bp ret setpixel: push bp mov bp,sp xor bx, bx mov cx, [bp+6] mov dx, [bp+10] mov al, [bp+14] mov ah, 0ch int 10h pop bp ret getch: push bp mov ah,0 int 16h mov ah,0 pop bp ret getPixelBlock: push bp mov cx, [bp+6] mov bx, image add bx, cx mov ax, [bx] pop bp ret section .data image db 11111110b, db 10011011b, db 11111100b, db 00010011b, db 00010000b, db 01101110b, db 10110000b, db 10111011b, db 01110101b, db 01100101b, db 11011011b, db 10100000b, db 00101110b, db 11000001b, db 01110001b, db 00000111b, db 11111010b, db 10101111b, db 11100000b, db 00011000b, db 00000000b, db 11010011b, db 01011111b, db 01101011b, db 11100100b, db 11101000b, db 00110101b, db 11001111b, db 01001111b, db 11100000b, db 00011011b, db 11010001b, db 00100111b, db 00000011b, db 10000000b, db 00000011b, db 10001111b, db 11111010b, db 00100000b, db 01010000b, db 01000110b, db 01011011b, db 10111010b, db 01001111b, db 01010101b, db 11010110b, db 10001110b, db 00101110b, db 10010001b, db 01111011b, db 00000101b, db 01100001b, db 10001111b, db 11101110b, db 11000001b main.c: __asm(".code16gcc\n"); int run(); int _start() { return run(); } // Dirty hack to code as I used to #include "ASM.inl" #include "Painter.inl" int run() { setVM(0x10); _brushSize = 5; drawLogo(30,30); uint ret = (uint)getch(); return ret>>5; } ASM.inl #ifndef __ASM_H__ #define __ASM_H__ typedef unsigned short int uint; typedef unsigned char uchar; void setpixel(uint x, uint y, uint color); void setVM(uint vm); uchar getch(); uchar getPixelBlock(uchar); #endif /* __ASM_H__ */ Painter.inl: /** * You can create other colors by using bitwise or */ enum Color { White = 0b0111, Black = 0b0000, Red = 0b0100, Green = 0b0010, Blue = 0b0001, Bright = 0b1000, }; int _brushSize = 5; void rect(uint x, uint y, uint width, uint height, uint color) { uint i,j; for (i=x; i<width+x; i++) { for (j=y; j<height+y; j++) { setpixel(i,j,color); } } } uint getColor(uchar element, uchar offset) { element = element & (1 << offset) >> offset; return element ? Black : White; } void drawLogo(uint x, uint y) { uchar current; uchar counter = 0; for (uint i=0; i<21; i++) { for (uint j=0; j<21; j++) { counter = i*21+j; current = getPixelBlock((uchar)counter/8); rect(x+i*_brushSize, y+j*_brushSize, _brushSize, _brushSize, getColor(current, counter%8)); } } } Compilation script: #!/bin/bash nasm -f elf32 module.asm -o module.o gcc -std=c99 -m32 -ffreestanding -masm=intel -c main.c -o main.o ld -m elf_i386 -Ttext=0x100 main.o module.o -o os.com objcopy os.com -O binary GCC version: 4.8.3 (Gentoo 4.8.3 p1.1, pie-0.5.9) NASM version: 2.11.05 DOSBox version: 0.74 What I am doing wrong? Maybe I should write directly into graphic memory or something like that? Or maybe I should change gcc optimizations?
The assembly code looks generally alright. You might want to check the interrupt calling sequences against the order of parameters on the stack by setting a breakpoint right on the int 10h and checking the register values. I haven't done that stuff for well over 20 years, and I'm rusty. You have at least two probable operator precedence problems. I don't think these do the right thing. element = element & (1 << offset) >> offset; current = getPixelBlock((uchar)counter/8); You have a hard-coded 'magic number': 21. I have no idea what that means. After that, the question is: where did it crash? Time to get that debugger stoked up and paying for itself. I meant to ask: why on earth write this stuff in assembly? You can easily call int 10h either directly from C, from embedded asm in C, or by a single wrapper function.
The way you define your data with a trailing comma introduces an extra byte with zero value. At least in my assembler! I think you need to double the value of CURRENT in the DRAWLOGO function in order to synchronize with the data. The function GETPIXELBLOCK recieves values from 0 To 55 which is 1 more than the data lines available!
Peculiar instruction sequence generated from straightforward C "if" lack condition
I am trying to debug some simple C code under gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 for x86-64. The code is built with CFLAGS += -std=c99 -g -Wall -O0 #include <errno.h> #include <stdio.h> #include <string.h> #pragma pack(1) int main (int argc, char **argv) { FILE *f = fopen ("the_file", "r"); /* error checking removed for clarity */ struct { short len; short itm [4]; char nul; } f00f; int n = fread (&f00f, 1, sizeof f00f, f); if (f00f.nul || f00f.len != 0x900 || f00f.itm [0] != 0xf00f || f00f.itm [1] != 0xf00f || f00f.itm [2] != 0xf00f || f00f.itm [3] != 0xf00f) { fprintf (stderr, "bitfile_hdr F00F data err:\n" "\tNUL: 0x%x\n" "\tlen: 0x%hx should be 0x900\n" "\tf00f: 0x%hx\n" "\tf00f: 0x%hx\n" "\tf00f: 0x%hx\n" "\tf00f: 0x%hx\n" , f00f.nul, f00f.len, f00f.itm[0], f00f.itm[1], f00f.itm[2], f00f.itm[3] ); return 1; } return 0; } The data matches what the test expects, and—weirdly—the error message displays the correct data: $ ./bit_parse bitfile_hdr F00F data err: NUL: 0x0 len: 0x900 should be 0x900 f00f: 0xf00f f00f: 0xf00f f00f: 0xf00f f00f: 0xf00f Running it under gdb and examining the structure also shows correct data. (gdb) p /x f00f $1 = {len = 0x900, itm = {0xf00f, 0xf00f, 0xf00f, 0xf00f}, nul = 0x0} Since that didn't make sense, I examined the instructions from inside gdb to reveal coding pathologies. The instructions corresponding to the non-functioning if are: 0x0000000000400736 <+210>: movzwl -0x38(%rbp),%eax 0x000000000040073a <+214>: movswl %ax,%r8d 0x000000000040073e <+218>: movzwl -0x3a(%rbp),%eax 0x0000000000400742 <+222>: movswl %ax,%edi 0x0000000000400745 <+225>: movzwl -0x3c(%rbp),%eax 0x0000000000400749 <+229>: movswl %ax,%r9d 0x000000000040074d <+233>: movzwl -0x3e(%rbp),%eax 0x0000000000400751 <+237>: movswl %ax,%r10d 0x0000000000400755 <+241>: movzwl -0x40(%rbp),%eax 0x0000000000400759 <+245>: movswl %ax,%ecx 0x000000000040075c <+248>: movzbl -0x36(%rbp),%eax 0x0000000000400760 <+252>: movsbl %al,%edx 0x0000000000400763 <+255>: mov $0x4008d8,%esi 0x0000000000400768 <+260>: mov 0x2008d1(%rip),%rax # 0x601040 <stderr##GLIBC_2.2.5> 0x000000000040076f <+267>: mov %r8d,0x8(%rsp) 0x0000000000400774 <+272>: mov %edi,(%rsp) 0x0000000000400777 <+275>: mov %r10d,%r8d 0x000000000040077a <+278>: mov %rax,%rdi 0x000000000040077d <+281>: mov $0x0,%eax 0x0000000000400782 <+286>: callq 0x400550 <fprintf#plt> 0x0000000000400787 <+291>: mov $0x6,%eax 0x000000000040078c <+296>: add $0x50,%rsp 0x0000000000400790 <+300>: pop %rbx 0x0000000000400791 <+301>: pop %r12 0x0000000000400793 <+303>: pop %rbp 0x0000000000400794 <+304>: retq It is really hard to see how this could implement a conditional. Anyone see why this (mis)behaves as it does?
Probably on your platform, short is 16-bit wide. Therefore no short can equal 0xf00f and the condition f00f.itm [0] != 0xf00f is always true. The compiler optimized accordingly. You may have meant unsigned short in the definition of struct f00f, but this is only one way to fix it, of course. You could also compare f00f.itm [0] to (short)0xf00f, but if you meant f00f.itm[i] to be compared to 0xf00f, you definitely should have used unsigned short in the definition.
short val = 0xf00f; assigns the value -4081 to val. You get hit by integer promotion rules. f00f.itm [0] != 0xf00f converts the short in f00f.itm [0] to an int, and that's -4081. 0xf00f as an int is 61455, and those two are not equal. Since the value is converted to an unsigned short when you print out the values (by using %hx), the issue isn't visible in the output. Use unsigned values in your struct since you seem to treat the values as unsigned: struct { unsigned short len; unsigned short itm [4]; char nul; } f00f; This sample program might make you understand what's going on a bit better: #include <stdio.h> int main(int argc,char *arga[]) { short x = 0xf00f; int y = 0xf00f; printf("x = 0x%hx y = 0x%x\n", x, y); printf("x = %d y = %d\n", x, y); printf("x==y: %d\n", x == y); return 0; }
How do I get info from the stack, using inline assembly, to program in c?
I have a task to do and I'm asking for some help. (on simple c lang') What I need to do? I need to check every command on the main c program (using interrupt num 1) and printing a message only if the next command is the same procedure that was sent earlier to the stack, by some other procedure. What I want to do? I want to take info from the stack, using inline assembley, and put it on a variable that can be compare on c program itself after returnning to c. (volatile) This is the program: #include <stdio.h> #include <dos.h> #include <conio.h> #include <stdlib.h> typedef void (*FUN_PTR)(void); void interrupt (*Int1Save) (void); //pointer to interrupt num 1// volatile FUN_PTR our_func; char *str2; void interrupt my_inter (void) //New interrupt// {volatile FUN_PTR next_command; asm { PUSH BP MOV BP,SP PUSH AX PUSH BX PUSH ES MOV ES,[BP+4] MOV BX,[BP+2] MOV AX,ES:[BX] MOV word ptr next_command,AX POP ES POP BX POP AX pop BP} if (our_func==next_command) printf("procedure %s has been called\n",str2);} void animate(int *iptr,char str[],void (*funptr)(), char fstr[]) { str2=fstr; our_func=funptr; Int1Save = getvect(1); // save old interrupt// setvect(1,my_inter); asm { pushf //TF is ON// pop ax or ax,100000000B push ax popf}} void unanimate() {asm { pushf //TF is OFF// pop ax and ax,1111111011111111B push ax popf} setvect (1,Int1Save); //restore old interrupt//} void main(void) {int i; int f1 = 1; int f2 = 1; int fibo = 1; animate(&fibo, "fibo", sleep, "sleep"); for(i=0; i < 8; i++) { sleep(2); f1 = f2; f2 = fibo; fibo = f1 + f2;} // for// unanimate();} // main// My question... Off course the problem is at "my inter" on the inline assembly. but can't figure it out. What am I doing wrong? (please take a look at the code above) I wanted to save the address of the pointer for the specific procedure (sleep) in the volatile our_func. then take the info (address to each next command) from the stack to volatile next_command and then finaly returnning to c and make the compare each time. If the same value (address) is on both variables then to print a specific message. Hope I'm clear.. 10x, Nir B
Answered as a comment by the OP I got the answer I wanted: asm { MOV SI,[BP+18] //Taking the address of each command// MOV DI,[BP+20] MOV word ptr next_command+2,DI MOV word ptr next_command,SI} if ((*our_func)==(*next_command)) //Making the next_command compare// printf("procedure %s has been called\n",str2);
Smallest method of turning a string into an integer(and vice-versa)
I am looking for an extremely small way of turning a string like "123" into an integer like 123 and vice-versa. I will be working in a freestanding environment. This is NOT a premature optimization. I am creating code that must fit in 512 bytes, so every byte does actually count. I will take both x86 assembly(16 bit) and C code though(as that is pretty easy to convert) It does not need to do any sanity checks or anything.. I thought I had seen a very small C implementation implemented recursively, but I can't seem to find anything for size optimization.. So can anyone find me(or create) a very small atoi/itoa implementation? (it only needs to work with base 10 though) Edit: (the answer) (edited again because the first code was actually wrong) in case someone else comes upon this, this is the code I ended up creating. It could fit in 21 bytes! ;ds:bx is the input string. ax is the returned integer _strtoint: xor ax,ax .loop1: imul ax, 10 ;ax serves as our temp var mov cl,[bx] mov ch,0 add ax,cx sub ax,'0' inc bx cmp byte [bx],0 jnz .loop1 ret Ok, last edit I swear! Version weighing in at 42 bytes with negative number support.. so if anyone wants to use these they can.. ;ds:bx is the input string. ax is the returned integer _strtoint: cmp byte [bx],'-' je .negate ;rewrite to negate DX(just throw it away) mov byte [.rewrite+1],0xDA jmp .continue .negate: mov byte [.rewrite+1],0xD8 inc bx .continue xor ax,ax .loop1: imul ax, 10 ;ax serves as our temp var mov dl,[bx] mov dh,0 add ax,dx sub ax,'0' inc bx cmp byte [bx],0 jnz .loop1 ;popa .rewrite: neg ax ;this instruction gets rewritten to conditionally negate ax or dx ret
With no error checking, 'cause that's for wussies who have more than 512B to play with: #include <ctype.h> // alternative: // #define isdigit(C) ((C) >= '0' && (C) <= '9') unsigned long myatol(const char *s) { unsigned long n = 0; while (isdigit(*s)) n = 10 * n + *s++ - '0'; return n; } gcc -O2 compiles this into 47 bytes, but the external reference to __ctype_b_loc is probably more than you can afford...
I don't have an assembler on my laptop to check the size, but offhand, it seems like this should be shorter: ; input: zero-terminated string in DS:SI ; result: AX atoi proc xor cx, cx mov ax, '0' ##: imul cx, 10 sub al, '0' add cx, ax lodsb jnz #b xchg ax, cx ret atoi endp
Write it yourself. Note that subtracting '0' from a digit gets the power-of-ten. So, you loop down the digits, and every time you multiply the value so far by 10, subtract '0' from the current character, and add it. Codable in assembly in no time flat.
atoi(p) register char *p; { register int n; register int f; n = 0; f = 0; for(;;p++) { switch(*p) { case ' ': case '\t': continue; case '-': f++; case '+': p++; } break; } while(*p >= '0' && *p <= '9') n = n*10 + *p++ - '0'; return(f? -n: n); }
And here is another one without any checking. It assumes a null terminated string. As a bonus, it checks for a negative sign. This takes 593 bytes with a Microsoft compiler (cl /O1). int myatoi( char* a ) { int res = 0; int neg = 0; if ( *a == '-' ) { neg = 1; a++; } while ( *a ) { res = res * 10 + ( *a - '0' ); a++; } if ( neg ) res *= -1; return res; }
Are any of the sizes smaller if you use -Os (optimize for space) instead of -O2 ?
You could try packing the string into BCD(0x1234) and then using x87 fbld and fist instructions for a 1980s solution but I am not sure that will be smaller at all as I don't remember there being any packing instruction.
How in the world are you people getting the executables so small?! This code generates a 316 byte .o file when compiled with gcc -Os -m32 -c -o atoi.o atoi.c and a 8488 byte executable when compiled and linked (with an empty int main(){} added) with gcc -Os -m32 -o atoi atoi.c. This is on Mac OS X Snow Leopard... int myatoi(char *s) { short retval=0; for(;*s!=0;s++) retval=retval*10+(*s-'0'); return retval; }