0

I've been learning assembly using the "Professional Assembly Language" book by Richard Blum and have gotten through all of it by writing assembly on MacOS, except of course a few of the "using files" exercises. Specifically, having trouble with appending a file. I can write to file, no problem, but not sure if have the correct "access mode values" for appending the file. According to the usr/include/sys/fcntl.h file MacOS likes using 0x0008 for appending files. The PAL book uses $02002(octal). (I suppose I could try doing this with library functions instead, but apparently those are just wrappers for the 'int' system calls, and just trying to understand how this all works).

Thanks for any help, and sorry if this is a dumb question or a did something really dumb. cheers.

Here's my code:

.data
filename:
.asciz "cpuid.txt"
output:
.asciz "The processor Vendor ID is 'xxxxxxxxxxxx'\n"

.bss
.lcomm filehandle, 4

.text
.globl _main
_main:
movl $0, %eax

# Get the CPUID and place the CPUID values (stored in ebx, edx and ecx) accordingly within,
# the correct address space, after the 'output' address.
cpuid
movl $output, %edi
movl %ebx, 28(%edi)
movl %edx, 32(%edi)
movl %ecx, 36(%edi)


# OPEN/CREATE A FILE:
movl $5, %eax
movl $filename, %ebx
movl $0x0008, %ecx      # Access mode values loaded into ECX        
                        #.... APPEND TEXT FILE, using a $02002(octal) according to PAL textbook
                        # on MacOS, APPEND mode is 0x0008 or $00007(octal)?  according to usr/include/sys/fcntl.h
movl $0644, %edx        # file permission values loaded into EDX

# For MacOS, we need to put all of this on the stack (in reverse order),
# and, add an additional 4-bytes of space on the stack,
# prior to the system call (with 'int')
pushl %edx
pushl %ecx
pushl %ebx
subl  $4, %esp
int   $0x80             # ...make the system call
addl  $16, %esp         # clear the stack


test %eax, %eax         # check the error code returned (stored in EAX) after attempting to open/create the file
js badfile              # if the value was negative (i.e., an error occurred, then jump)
movl %eax, filehandle   # otherwise, move the error code to the 'filehandle'


# WRITE TO FILE:
movl $4, %eax
movl filehandle, %ebx
movl $output, %ecx
movl $42, %edx

# once again, for MacOS, put all of this on the stack,
# and, add an additional 4-bytes of space on the stack
pushl %edx
pushl %ecx
pushl %ebx
subl $4, %esp
int $0x80
addl $16, %esp          # and, again, clear the stack

test %eax, %eax
js badfile



# CLOSE THE FILE:
movl $6, %eax
movl filehandle, %ebx

# okay, move it onto the stack again (only one parameter on stack for closing this time)
pushl %ebx
subl $4, %esp
int $0x80

addl $8, %esp

badfile:
subl $9, %esp
movl %eax, %ebx
movl $1, %eax
int $0x80
Paweł Łukasik
  • 3,893
  • 1
  • 24
  • 36
Frank
  • 11
  • 4
  • Is this a duplicate of https://stackoverflow.com/a/9622244/2189500? – David Wohlferd Sep 04 '17 at 22:00
  • Putting $02001 in %ecx, when opening the file, does not seem to work. If I use that access mode code and then try to append the file, the file doesn't appear to append in mac osx (MacOS) (despite being able to write to the file above "cpuid.txt" if it was empty). – Frank Sep 05 '17 at 04:45
  • If `O_APPEND` is 0x8 on mac, then I'd expect `O_WRONLY | O_APPEND` to be 0x9. – David Wohlferd Sep 05 '17 at 05:07
  • okay, after converting a C program that uses O_APPEND and checking the values put on the stack, I figured out the append value for Mac OS X (MacOS)... it's $012(octal) or 0x0a. – Frank Sep 05 '17 at 05:34
  • Yes, you are correct. 0x9 (O_WRONLY | O_APPEND) also works. The C program I was looking at used O_RDWR|O_APPEND, which would mean 2+8, or 0x0a. So, 0x09 or 0x0a into ECX above (instead of 0x0008) works. Thanks for helping to clear this up. – Frank Sep 05 '17 at 05:44
  • You can use `strace` to decode what args you actually passed to system calls. And yes, you should always use the constants for your OS from your header files, not constants from some book. Especially when the book was written for a different OS! – Peter Cordes Sep 07 '17 at 20:26

1 Answers1

1

Below is the corrected assembly language code version (AT&T style) for appending a file on mac os x (MacOS).

Compile your 'myfile.s' assembly file in Mac Terminal using the 'as' and 'ld' commands:

as -m32 -o myfile.o myfile.s

ld -e _main -o myfile myfile.o

.data
filename:
.asciz "cpuid.txt"
output:
.asciz "The processor Vendor ID is 'xxxxxxxxxxxx'\n"

.bss
.lcomm filehandle, 4

.text
.globl _main
_main:
movl $0, %eax

# Get the CPUID and place the CPUID values (stored in ebx, edx and ecx) accordingly within,
# the correct address space, after the 'output' address.
cpuid
movl $output, %edi
movl %ebx, 28(%edi)
movl %edx, 32(%edi)
movl %ecx, 36(%edi)


# OPEN/CREATE A FILE:
movl $5, %eax
movl $filename, %ebx
movl $0x09, %ecx      # Access mode values loaded into ECX        
                      # on Linux, APPEND TEXT FILE using a $02002(octal) according to "Professional Assembly Language" (PAL) textbook
                      # however, on Mac OS X (MacOS), APPEND mode is 0x0008, according to usr/include/sys/fcntl.h
                      # ... so for write (0x01) and append (0x08) access (O_WRONLY | O_APPEND), the value becomes 0x09
                      # (for read/write (0x02) and append (0x08) access (O_RDWR|O_APPEND), the value would be 0x0a)

movl $0644, %edx      # file permission values loaded into EDX

# For MacOS, we need to put all of this on the stack (in reverse order),
# and, add an additional 4-bytes of space on the stack,
# prior to the system call (with 'int')
pushl %edx
pushl %ecx
pushl %ebx
subl  $4, %esp
int   $0x80             # ...make the system call
addl  $16, %esp         # clear the stack


test %eax, %eax         # check the error code returned (stored in EAX) after attempting to open/create the file
js badfile              # if the value was negative (i.e., an error occurred, then jump)
movl %eax, filehandle   # otherwise, move the error code to the 'filehandle'


# WRITE TO FILE:
movl $4, %eax
movl filehandle, %ebx
movl $output, %ecx
movl $42, %edx

# once again, for MacOS, put all of this on the stack,
# and, include an additional 4-bytes of space on the stack,
# (stack grows downward, thus the 'subl' instruction) prior to the 'int' system call
pushl %edx
pushl %ecx
pushl %ebx
subl $4, %esp
int $0x80
addl $16, %esp          # and, again, clear the stack

test %eax, %eax
js badfile



# CLOSE THE FILE:
movl $6, %eax
movl filehandle, %ebx

# okay, move it onto the stack again (only one parameter on stack for closing this time)
pushl %ebx
subl $4, %esp
int $0x80

addl $8, %esp

badfile:
subl $9, %esp
movl %eax, %ebx
movl $1, %eax
int $0x80
Frank
  • 11
  • 4
  • You can `#include ` to get system call number constants, so you can do something like `mov $__NR_write, %eax`. And instead of putting args into the registers for the Linux ABI, you should just push directly since you're using the 32-bit FreeBSD system call ABI. See https://stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-on-x86-64. (See also https://stackoverflow.com/tags/x86/info for more links) – Peter Cordes Sep 07 '17 at 20:20
  • Anyway, you can define some symbolic constants with `.equ`, or use `gcc -dM` to dump the macro definition from your `sys/fcntl.h` into a header you can include from asm (that doesn't contain any non-CPP C definitions). Then you can write `push $0666` / `push $(O_WRONLY|O_APPEND)` / `push $filename`. (Use 0666 for permissions to let `umask` do its job.) Actually, the mode is never used if your flags don't include `O_CREAT`, but whatever. – Peter Cordes Sep 07 '17 at 20:23
  • Much belated but your help was much appreciated. (Still writing assembly.) Cheers. – Frank Jun 26 '23 at 17:36