'Write returns different error from main than within a function called from main?

This issue is as bizarre as it sounds in the title. I've created an _ft_write in Assembler for MacOSX, which sets errno in case of an error. This is my _ft_write:

extern ___error
global _ft_write

section .text
    _ft_write:
        mov rax, 0x2000004
        clc
        syscall
        jc error
        ret
    
    error:
        push rax
        call ___error
        pop rbx
        mov [rax], ebx
        mov rax, -1
        ret

Experimenting with my _ft_write and the original write for C, I've written a main that calls _ft_write and write with the same parameters, and prints the ERRNO and the associated Error Message in case of an error.

If I call both _ft_write and write from the main and pass them a NULL string as second parameter, both versions return ERRNO "14, Bad address". If I call them by sending all the same parameters to another function, and then call _ft_write and write within that function - my _ft_write continues to return "14, Bad address", as you'd expect, but C's write returns "22, Invalid argument"!

So with this program:

int main(void)
{
    int bytes;
    int *string;

    string = NULL;
    printf("Write Res: %d\n", (bytes = ft_write(1, string, 13)));
    if (bytes < 0)
    {
        printf("My Errno: %d\n", errno);
        perror("\0");
    }
    printf("Write Res: %d\n", (bytes = write(1, string, 13)));
    if (bytes < 0)
    {
        printf("C's Errno: %d\n", errno);
        perror("\0");
    }
    return (0);
}

I get:

Write Res: -1
My Errno: 14
Bad address
Write Res: -1
C's Errno: 14
Bad address

Yet, with this program:

void    testwrite(int fd, char *string, int bytes)
{
    printf("Write Res: %d\n", (bytes = ft_write(fd, string, bytes)));
    if (bytes < 0)
    {
        printf("My Errno: %d\n", errno);
        perror("\0");
    }
    printf("Write Res: %d\n", (bytes = write(fd, string, bytes)));
    if (bytes < 0)
    {
        printf("C's Errno: %d\n", errno);
        perror("\0");
    }
}


int main(void)
{
    testwrite(1, NULL, 13);
    return (0);
}

I get:

Write Res: -1
My Errno: 14
Bad address
Write Res: -1
C's Errno: 22
Invalid argument

As far as I can see there is nothing that changes that would explain why the C write should change the error message. Does anyone know what is going on?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source