diff --git a/tools/banjo/banjo/src/backends/abigen.rs b/tools/banjo/banjo/src/backends/abigen.rs
index e9577f4f14b00e12d514c066a621bb8495b3cbd3..80a0fe0569f3bae2200c89ace1146b4c5609dab5 100644
--- a/tools/banjo/banjo/src/backends/abigen.rs
+++ b/tools/banjo/banjo/src/backends/abigen.rs
@@ -52,16 +52,20 @@ impl ValuedAttributes {
         ValuedAttributes(result)
     }
 
-    // Returns the value for a given name, prepended with a leading space. Note
-    // that this name is the LHS of the string value, not the outer attribute
-    // name. In the example above, the name would be "p0" or "p1", rather than
-    // "zippy".
-    fn get_arg_spaced(&self, name: &str) -> String {
+    // Returns the value for a given name, prepended with prefix.
+    // Note that this name is the LHS of the string value, not the outer
+    // attribute name. In the example above, the name would be "p0" or "p1",
+    // rather than "zippy".
+    fn get_arg_with_prefix(&self, name: &str, prefix: &str) -> String {
         match self.0.get(name) {
-            Some(annot) => " ".to_owned() + &annot,
+            Some(annot) => prefix.to_owned() + &annot,
             _ => String::default(),
         }
     }
+
+    fn get_arg(&self, name: &str) -> String {
+        self.get_arg_with_prefix(name, "")
+    }
 }
 
 pub fn to_c_name(name: &str) -> String {
@@ -186,8 +190,8 @@ fn get_in_params(
     m.in_params
         .iter()
         .map(|(name, ty)| {
-            let extra = arg_types.get_arg_spaced(name);
-            let arrsize = array_sizes.get_arg_spaced(name);
+            let extra = arg_types.get_arg_with_prefix(name, " ");
+            let arrsize = array_sizes.get_arg(name);
             match ty {
                 ast::Ty::Identifier { id, .. } => {
                     if id.is_base_type() {
@@ -256,7 +260,7 @@ fn get_out_params(
             if index == 0 {
                 return ty_name;
             }
-            let extra = arg_types.get_arg_spaced(name);
+            let extra = arg_types.get_arg_with_prefix(name, " ");
             match ty {
                 ast::Ty::Handle { .. } => format!("{}: {}{}", to_c_name(name), ty_name, extra),
                 _ => format!("{}: {}{}", to_c_name(name), ty_name, extra),
diff --git a/tools/banjo/banjo/test/abigen/abigen-protocol-markup.abigen.out b/tools/banjo/banjo/test/abigen/abigen-protocol-markup.abigen.out
new file mode 100644
index 0000000000000000000000000000000000000000..cade8036d98016352b71bd6df82002d9866baa51
--- /dev/null
+++ b/tools/banjo/banjo/test/abigen/abigen-protocol-markup.abigen.out
@@ -0,0 +1,30 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# WARNING: THIS FILE IS MACHINE GENERATED. DO NOT EDIT.
+# Generated from the banjo.examples.abigen.protocol.markup banjo file
+
+#^ This is a short description.
+syscall an_excellent_thing
+    (clock_id: zx_clock_t)
+    returns (zx_time_t);
+
+#^ Very much like an object_wait_one.
+#! handle must have ZX_RIGHT_WAIT.
+syscall do_another_thing blocking
+    (handle: zx_handle_t, signals: zx_signals_t, deadline: zx_time_t)
+    returns (zx_status_t, observed: zx_signals_t optional);
+
+#^ Fancy hacks for array sizes.
+#! handle must be of type ZX_OBJ_TYPE_FIFO and have ZX_RIGHT_READ.
+syscall a_third_thing
+    (handle: zx_handle_t, elem_size: size_t, data: any[count*elem_size] OUT, count: size_t)
+    returns (zx_status_t, actual_count: size_t optional);
+
+syscall the_attributes blocking const internal test_category1 test_category2 vdsocall
+    ()
+    returns ();
+
+syscall noreturn_handling noreturn
+    ();
diff --git a/tools/banjo/banjo/test/banjo/abigen-protocol-markup.test.banjo b/tools/banjo/banjo/test/banjo/abigen-protocol-markup.test.banjo
new file mode 100644
index 0000000000000000000000000000000000000000..1f558076843cac823c85d69d4917fdc2e33e67e5
--- /dev/null
+++ b/tools/banjo/banjo/test/banjo/abigen-protocol-markup.test.banjo
@@ -0,0 +1,31 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library banjo.examples.abigen.protocol.markup;
+
+protocol Api {
+    [shortdesc="This is a short description."]
+    an_excellent_thing(zx.clock clock_id) -> (zx.time time);
+
+    [shortdesc="Very much like an object_wait_one.",
+     rights="handle must have ZX_RIGHT_WAIT.",
+     blocking,
+     argtype="observed optional"]
+    do_another_thing(handle handle, zx.signals signals, zx.time deadline) ->
+        (zx.status status, zx.signals observed);
+
+    [shortdesc="Fancy hacks for array sizes.",
+     rights="handle must be of type ZX_OBJ_TYPE_FIFO and have ZX_RIGHT_READ.",
+     argtype="data OUT",
+     argtype="actual_count optional",
+     arraysize="data count*elem_size"]
+    a_third_thing(handle<fifo> handle, usize elem_size, array<voidptr>:N data, usize count) ->
+        (zx.status status, usize actual_count);
+
+    [blocking, const, internal, test_category1, test_category2, vdsocall]
+    the_attributes() -> ();
+
+    [noreturn]
+    noreturn_handling();
+};
diff --git a/tools/banjo/banjo/test/codegen_tests.rs b/tools/banjo/banjo/test/codegen_tests.rs
index b3413677266fec0ba995c5af044d77e2b0120ded..49284e4d9c6c627ef2af10a4ed9ba3b9c76458d9 100644
--- a/tools/banjo/banjo/test/codegen_tests.rs
+++ b/tools/banjo/banjo/test/codegen_tests.rs
@@ -233,10 +233,18 @@ mod abigen {
     // Review" bit on Gerrit.
 
     codegen_test!(empty, AbigenBackend, ["banjo/empty.test.banjo"], "abigen/empty.abigen.out");
+
     codegen_test!(
         abigen_protocol_basic,
         AbigenBackend,
         ["banjo/abigen-protocol-basic.test.banjo"],
         "abigen/abigen-protocol-basic.abigen.out"
     );
+
+    codegen_test!(
+        abigen_protocol_markup,
+        AbigenBackend,
+        ["banjo/abigen-protocol-markup.test.banjo"],
+        "abigen/abigen-protocol-markup.abigen.out"
+    );
 }