1

Could anybody tell me why does there occur a segfault when there is a call to printf in here?

32bit NASM Code:

    global replaceDigitsWithAsterisk
    section .text

replaceDigitsWithAsterisk:      ;Arg: ptr to string
    push        ebp             ;Save last frame pointer
    mov         ebp, esp        ;Save current frame pointer
    mov         ebx, dword [ebp + 8]  ;Save address of string
                                ;[ebp + 4] return address, 
    push        eax             ;save address of string
replaceLoop:
    mov         al, byte[ebx]   ;store current char in al
    cmp         al, 0          ;compare if is equal zero
    je          replaceLoopEnd  ;if not null terminator continue

    cmp         al, '0'         ;compare with ASCII 0
    jl          increment
    cmp         al, '9'         ;compare with ASCII 9
    jg          increment         ;insert * if > 0

increment:
    add         ebx, 1          ;increment string pointer by 1 byte
    jmp         replaceLoop     ;unconditionally jump

replace:                        ;somehow cmovb and cmova are not working for my nasm ;__;
    mov         byte[ebx], '*'  
    jmp         increment

replaceLoopEnd:
    pop         eax             ;Restore address of result
    pop         ebp             ;Restore last frame pointer
    ret                         ;sets instruction pointer to return address

C Code:

#include <stdio.h>

char* replaceDigitsWithAsterisk(char* source);

int main()
{
    char s1[] = "Wind 99 the hill";
    char s2[] = "Litwo, 1234450 moja";
    char s3[] = "Tak jak 333678 to";
    char s4[] = "Ebe Ebe Ebe";
    char* result;
    result = replaceDigitsWithAsterisk(s1);
    printf("Result 1: %s\n", result);
    result = replaceDigitsWithAsterisk(s2);
    printf("Result 2: %s\n", result);
    result = replaceDigitsWithAsterisk(s3);
    printf("Result 3: %s\n", result);
    result = replaceDigitsWithAsterisk(s4);
    printf("Result 4: %s\n", result);
    return 0;
}

Moreover it seems as if cmovb and cmova instructions are not working with my nasm (newest) and on Windows it works normally

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Celeborth
  • 48
  • 4
  • 2
    This might or might not be the cause of the fault, but `ebx` is a callee-saved register. You must preserve it for your caller. `cmov` should work, show what exactly you tried and what error you got. – Jester Nov 18 '18 at 11:58
  • 2
    On top of what Jester said: You save and restore _EAX_ which you never put the address in as suggested by the comments. – Michael Petch Nov 18 '18 at 12:36
  • @MichaelPetch good catch. Trying to print **that** is probably the direct cause of the fault. – Jester Nov 18 '18 at 12:37
  • 1
    I also suspect you meant to place `increment:` `add ebx, 1 ;increment string pointer by 1 byte` `jmp replaceLoop ;unconditionally jump` after `replace` and note before it – Michael Petch Nov 18 '18 at 12:44
  • @Jester thank you for pointing that out, this fixed the issue. I have tried using `cmovb byte[ebx], '*'`and similar with `cmova` It returned me this error: invalid combination of opcode and operands – Celeborth Nov 18 '18 at 14:09
  • @MichaelPetch Right, I have moved this section below and removed unnecessary jump, thanks for pointing that out. – Celeborth Nov 18 '18 at 14:09
  • 1
    There is no `cmov` which takes an immediate. Consult the instruction set reference for allowed operands. – Jester Nov 18 '18 at 14:13
  • most likely your string arrays are allocated in a read-only section. you got a crash on an invalid modification access. – Serge Nov 18 '18 at 16:16
  • 1
    @Serge : no in this case he initialized them as arrays with `[]` instead of string literals via `*` . The initialization of `s1[]`, `s2[]`, `s3[]`, `s4[]` will be to read/write memory. – Michael Petch Nov 18 '18 at 20:45
  • "On Windows it's working normally". Q: What platform are you experiencing the problem on? What C runtime library are you getting "printf" from? – paulsm4 Nov 18 '18 at 22:57
  • There's also no `cmov` with a memory *destination*. If you want conditional / predicated stores, you'll need to use AVX512 mask registers for `vmovss` or something like that. There's also no `cmov` with byte operand-size. Also, `a` and `b` are different conditions than `g` and `l`. – Peter Cordes Nov 18 '18 at 23:00
  • Anyway, your function clobber's the compiler's EBX. It's a call-preserved register in all the calling conventions on Windows and Linux, so if your code *doesn't* crash after returning to main then you just got lucky. (Because of different code-gen from different compilers on your Windows vs. Linux.) Changing the caller would also change whether or not the code happened to depend on the value of EBX. **If you're using GCC on a modern Linux distro, it's probably making PIE executables and using EBX as the GOT pointer (for referencing the format strings).** – Peter Cordes Nov 18 '18 at 23:10
  • Peter, I think the most obvious issue isn't just related to EBX, but the fact that he's likely not returning the string address back through EAX properly (he uses that to pass to `printf`). It may have been on other platforms that EAX may have held the string address prior to calling his function and it just happened to work. – Michael Petch Nov 19 '18 at 01:08

0 Answers0