I'm trying to get the address that is pointed to by UnsafeMutableRawPointer, but I'm unable to do so. I'm also new to Swift so I might be missing something or doing it completely wrong. Preferably I would like to cast the raw value into a CChar.
Note to passers-by: much of my answer won't make sense, as it doesn't answer the initial question above, but rather the question(s) that arose in the chat with OP.
Took me a few hours, but now that I've learned some assembly, I can answer some questions.
CChar
is a C Char
... literally. It represents the char
type of C
. It's a typealias
to Int8
. It's a single byte. You can't use this like a pointer type, as those are 8 bytes (on 64 bit machines).
You don't need all this UnsafeMutableRawPointer
boilerplate, and you certainly don''t need to access its raw value. You can pass arrays directly where pointers are expected.
When a function is declared as taking an UnsafePointer argument, it can accept any of the following: ...
- A [Type] value, which is passed as a pointer to the start of the array.
You were experiencing issues were your mutation of 0x8(%rdi)
did not seem to be reflected on the Swift side. The issue here is that you're writing at an offset of 8 bytes, but then print(a.load(as: void_star.self))
is reading the first byte. You're reading a byte you never modified.
I did some further exploration. Here's the loot from my adventure:
@_silgen_name("incrementByValue")
func incrementByValue(_: Int64)
@_silgen_name("incrementByReference")
func incrementByReference(_: inout Int64)
@_silgen_name("return1234")
func return1234() -> Int64
@_silgen_name("incrementElements")
func incrementElements(of _: UnsafeRawPointer, count _: Int)
var a: Int64 = 100
print("\"a\" before \"incrementByValue(a)\": \(a)")
incrementByValue(a)
print("\"a\" after \"incrementByValue(a)\": \(a)\n")
var b: Int64 = 200
print("\"b\" before \"incrementByValue(b)\": \(b)")
incrementByReference(&b)
print("\"b\" after \"incrementByValue(b)\": \(b)\n")
print("return1234() returned: \(return1234())\n")
var array: [Int64] = Array(0...5)
print("\"array\" before incrementElements(of: array, count: array.count): \n\t\(array)")
incrementElements(of: array, count: array.count)
print("\"array\" after incrementElements(of: array, count: array.count): \n\t\(array)\n")
.text
.globl _incrementByValue
.globl _incrementByReference
.globl _return1234
.globl _incrementElements
// A test routine that demonstrates operating on a value
_incrementByValue:
// %rdi contains a copy of the argument passed in.
// Changes here won't be reflected back in Swift
incq %rdi
ret
// A test routine that demonstrates operating on a reference
_incrementByReference:
// %rdi contains a reference tp the argument passed in.
// Changes to the reference itself won't be reflected back in Swift,
// but changes to the referenced memory will.
incq (%rdi)
ret
// A test routine that demonstrates the use of %rax for returning a value
_return1234:
movq $1234, %rax // return value is in rax
ret
//A test routine that demonstrates operating on an array
_incrementElements:
// %rdi: Pointer to first of n Int64 elements
// %rsi: the array count, n
movq %rsi, %rcx // Set loop counter (%rcx) to n
aLoop:
incq (%rdi) // increment value pointer to by %rdi
add $8, %rdi // advance pointer by 8 bytes
loop aLoop // loop back to aLoop if rcx > 0
ret
Compile, link and run with:
llvm-g++ -c exampleASM.s &&
swiftc -c exampleSwift.swift &&
ld exampleASM.o exampleSwift.o -o exampleBinary -force_load /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_macosx.a -framework CoreFoundation -macosx_version_min 10.12.0 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -lobjc -lSystem -arch x86_64 -L /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -rpath /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -no_objc_category_merging &&
./exampleBinary
Output:
"a" before "incrementByValue(a)": 100
"a" after "incrementByValue(a)": 100
"b" before "incrementByValue(b)": 200
"b" after "incrementByValue(b)": 201
return1234() returned: 1234
"array" before incrementElements(of: array, count: array.count):
[0, 1, 2, 3, 4, 5]
"array" after incrementElements(of: array, count: array.count):
[1, 2, 3, 4, 5, 6]